要取得大頭貼照,如果使用API request,加上picture即可得到大頭貼照,如:me?fields=id,name,picture,即可在回傳的JSON中取得圖片的位址,但這時取回來的圖片會比正常大小還要小,而且此方法還需要access_token。
要取得不同大小的大頭貼照,有個更輕鬆的方法:http://graph.facebook.com/{id}/picture?type=normal 直接使用此網址,將id換成想呈現的userId即可,此網址將會redirect到對應的圖片位址,且此方法不需要access_token。
在這個網址中,type可為small, normal, album, large, square,分別為不同解析度的照片大小。
以Facebook的創始人Mark Zuckerberg為例,userId為4,則要顯示的網址如下:
50*50:
http://graph.facebook.com/4/picture?type=small
http://graph.facebook.com/4/picture?type=album
http://graph.facebook.com/4/picture?type=square
100*100:
http://graph.facebook.com/4/picture?type=normal
200*200:
http://graph.facebook.com/4/picture?type=large
不能理解的是為什麼small, album, square所得到的大小都一樣,還不知道差在哪。
North Coding Zone
keep studying and trying to share something (新網站已移至:https://ssk7833.github.io)
2015年8月25日 星期二
2015年7月12日 星期日
Facebook Graph API 回傳指定語言姓名(Language-specific name)
玩Facebook Graph API玩了一陣子才發現回傳的姓名總是是英文的,才想到若是有回傳中文姓名的需求時該怎麼辦,如此下去一找才發現關鍵字是Language-specific name,而要如何在Facebook Graph API中顯示為中文則可以參考這篇中的locale:Modifying API Requests。
其實只要在API request中加上
其實只要在API request中加上
&locale=zh_TW
即可得到中文姓名,如:me?fields=id,name&locale=zh_TW
,只是有趣的是我稍微測了一下locale給以開頭en_
以外的任何值都會取得中文名稱,還以為預設會以英文為主。
2015年7月1日 星期三
使用parse.com Cloud Code Hosting進行Facebook登入存取 - 3
繼上一篇成功截取出使用者資料後,發現除了基本資料外,朋友、按讚的資訊等資料其實都抓不出來,原因是因為沒有給予app存取這些資訊的權限。要求權限的話可以透過OAuth來索取access token,其範例網址如下:
https://www.facebook.com/dialog/oauth?client_id={appId}&redirect_uri={redirectURI}
這是一個截取基本權限的網址,appId指的是每一個app獨立的ID,而redirectURI是當OAuth通過後,會送發一串code到這個redirectURI去,而若需要要求其他權限,可以增加scope屬性如下:
https://www.facebook.com/dialog/oauth?client_id={appId}&redirect_uri={redirectURI}&scope={accessPermissions}
這個scope以逗號作為分隔,填在裡面的將會在facebook dialog中要求權限。
講了這麼多,但以第一篇中使用了parse-facebook-user-session該怎麼修改呢?稍微翻了它的source code後發現它在實作上並沒有保留scope欄位,因此我便把scope加上去了,可以由此瀏覽:parse-facebook-user-session
UPDATE:原Repository已經將此功能merge上去,直接使用原本的即可
UPDATE:原Repository已經將此功能merge上去,直接使用原本的即可
使用方式的話則與先前的沒什麼差別,只是可以選擇多填一個scope欄位,範例如下:
app.use(parseFacebookUserSession({ clientId: 'YOUR_FB_CLIENT_ID', appSecret: 'YOUR_FB_APP_SECRET', redirectUri: '/login', scope: 'user_friends,user_likes', // 要求friends與like資訊 }));
至於有哪些權限可以要求,可以當https://developers.facebook.com/tools/explorer/中,點選Get Access Token來參考,並且在下面做測試。
不過要注意的有像是user_friends這項,如果在API v2.0以上的版本上要求資訊的話,只會列出同樣有授權此app的好友出來,開了幾個test users測試的確如此:
很可憐沒有朋友授權此APP:
有朋友也授權此APP:
至於怎麼得到test user的access token,我是利用parse.com的API Console,Endpoint填入users且Use Master Key改成Yes,send request後即可在response中看到access token,即可複製此token到https://developers.facebook.com/tools/explorer/中做測試,如下圖。
{ "id": "104342733239984", "name": "Hello world", "friends": { "data": [], "summary": { "total_count": 1 } } }可以看到summary中,total_count為1,但data中無資料。
有朋友也授權此APP:
{ "id": "1421116644879628", "name": "Doraemon Cat", "friends": { "data": [ { "name": "Open Graph Test User", "id": "1414470195545509" }, { "name": "Monkey D Luffy", "id": "100347703641647" } ], "paging": { "next": "https://graph.facebook.com/1421116644879628/friends?limit=25&offset=25&__after_id=enc_AdAMpWdRxSLZAvND6bEd0htyyGsZAZBvzP6jzoAIZBKS9EiBSndZCNZC3S1AC5TEYchbuuBSV0xvg7ziwO4Cdt843yZApF" }, "summary": { "total_count": 2 } } }可以看到此test user有兩個朋友也都有安裝此app。
至於怎麼得到test user的access token,我是利用parse.com的API Console,Endpoint填入users且Use Master Key改成Yes,send request後即可在response中看到access token,即可複製此token到https://developers.facebook.com/tools/explorer/中做測試,如下圖。
2015年6月20日 星期六
使用parse.com Cloud Code Hosting進行Facebook登入存取 - 2
延續上一篇,成功使用facebook登入parse.com的使用者資訊後,接著就是怎麼從使用者資訊中取得facebook的資料了。
以上圖的Facebook Test Users為例,建立完的使用者可以由parse.com的Data中看到,不過authData卻只顯示了Facebook的ID,因此我們可以先透過API Console來對users作存取,這裡要注意的是Use Master Key記得要選Yes,否則會沒有權限看authData的內容;users後面的參數為objectId,若不放置則會列出全部符合的資料。
在Response中的內容:
當然,別忘記userMasterKey...
UPDATE:使用parse.com Cloud Code Hosting進行Facebook登入存取 - 3
以上圖的Facebook Test Users為例,建立完的使用者可以由parse.com的Data中看到,不過authData卻只顯示了Facebook的ID,因此我們可以先透過API Console來對users作存取,這裡要注意的是Use Master Key記得要選Yes,否則會沒有權限看authData的內容;users後面的參數為objectId,若不放置則會列出全部符合的資料。
在Response中的內容:
{ "authData": { "facebook": { // 不要想對這組access_token亂來,因為是test user XD "access_token": "CAAMCk3Pv7SkBAEjfvRaG4SrC8k3CXak1843iisuUJiIK9gYV9PNFRraXi9gxYVBJO83zsvzFO91dcACevKwinxAVPNCUeEv0UPWsmv7DZBlqPjtZCCnEBcMBKpU7ikoj9OKo1ZCwzi3wmTycsB2avHT1SiBxLUF5ZAHTaT9XDNtz1phGZCk0lltOY5agj0JGQ9ezNGmOsvUmdpKFASx5K", "expiration_date": "2015-08-15T17:52:46.495Z", "id": "118563748477765" } }, "createdAt": "2015-06-16T17:52:48.623Z", "name": "Super Mario", "objectId": "wmVm7Qb1Fc", "sessionToken": "jEKKzfbDcIN0CmBIvsdZR9Aoc", "updatedAt": "2015-06-17T07:57:08.934Z", "username": "3GwDpgmuqmfnyGYINNI27W9fO" }已經知道存放在哪裡之後,接下來就是利用cloud code function建立資料存取了!在這裡我用名字與圖片作範例,參考了stackoverflow這篇的回答稍微修改了一下:
當然,別忘記userMasterKey...
Parse.Cloud.define("facebook", function(request, response) { Parse.Cloud.useMasterKey(); new Parse.Query(Parse.User).get(request.params.user_id).then(function(user) { var authData = user.get("authData"); // Quit early for users who aren't linked with Facebook if (authData === undefined || authData.facebook === undefined) { response.success(null); return; } return Parse.Cloud.httpRequest({ method: "GET", url: "https://graph.facebook.com/me", params: { access_token: authData.facebook.access_token, fields: "name, friends", }, }); }).then(function(json) { response.success(json.data); // Promises will let you bubble up any error, similar to a catch statement }, function(error) { response.error(error); }); });在Express中call建立好的cloud host function:
app.get('/test', fbLogin, function(req, res) { var user = Parse.User.current(); Parse.Cloud.run('facebook', { user_id: user.id }, { success: function(results) { res.send('Congrats, you are logged in, ' + results.name + '!' + ''); }, error: function(error) { console.log("error :" + error); } }); });若是成功的話就能在自己的URL中看到如下圖的結果了!
UPDATE:使用parse.com Cloud Code Hosting進行Facebook登入存取 - 3
使用parse.com Cloud Code Hosting進行Facebook登入存取 - 1
parse.com在Javascript SDK中提供了使用者的存取,其中包含Facebook的整合,但Javascript終究是前端,有些不想讓client end知道的還是放在後端處理比較好。然而parse.com所提供的cloud code所使用的目前雖是node.js,會讓開發者很想直接把Javascript SDK的Facebook部分塞進去看能不能跑,乍看之下很合理,但實際上就是不行,因為以parse.com Javascript SDK在要求登入時會跳出另一個瀏覽器視窗以要求登入facebook及權限給予,而這個視窗當然沒有辦法在server end中呈現並要求client end進行認證。
在官方論壇上也有人發表過此問題:Interacting with the Facebook API in Cloud Code
所得到的回答是:
Unfortunately, the Facebook JavaScript SDK is not made to work outside of a browser, so using it directly from Cloud Code is not supported at the moment.
You can, however, get the authData from the current user in cloud code and use that to make a REST call to Facebook's graph API manually.
因此我轉而研究使用OAuth方式來登入Facebook,除了跳轉出的頁面比較美觀外(不會產生另一個瀏覽器視窗),也不用擔心暴露資訊給clent end,參考資料有這兩篇:
網站利用 Facebook 帳號登入 (使用 OAuth)
10分鐘理解OAuth和facebook登入原理
這篇以python Django framework實作,其實看code好像也蠻容易理解的:Ghetto Facebook Registration with Django
後來正當我開始打算實作時,我找到了parse-facebook-user-session,原來parse.com早就把這個寫好了,根本不用自己去寫了,只需要按照他的說明一步一步來就行了(吧)!
結果證明事情果然不是我想的這麼簡單,不管怎麼弄就是跳出209 invalid session token,花了一段時間後找到parse.com自己發的文章Session Migration Tutorial,才知道把這個選項關掉就行了,我花了這麼久到底在幹麻!
總之,關閉這個選項後就成功了,parse.com的資料庫也會成功紀錄登入過的使用者,事情完成一半,其餘的就是登入的使用者資料該怎麼讀取出來了~
UPDATE:使用parse.com Cloud Code Hosting進行Facebook登入存取 - 2
UPDATE:在GitHub上新增了範例程式:demo, GitHub
在官方論壇上也有人發表過此問題:Interacting with the Facebook API in Cloud Code
所得到的回答是:
Unfortunately, the Facebook JavaScript SDK is not made to work outside of a browser, so using it directly from Cloud Code is not supported at the moment.
You can, however, get the authData from the current user in cloud code and use that to make a REST call to Facebook's graph API manually.
因此我轉而研究使用OAuth方式來登入Facebook,除了跳轉出的頁面比較美觀外(不會產生另一個瀏覽器視窗),也不用擔心暴露資訊給clent end,參考資料有這兩篇:
網站利用 Facebook 帳號登入 (使用 OAuth)
10分鐘理解OAuth和facebook登入原理
這篇以python Django framework實作,其實看code好像也蠻容易理解的:Ghetto Facebook Registration with Django
後來正當我開始打算實作時,我找到了parse-facebook-user-session,原來parse.com早就把這個寫好了,根本不用自己去寫了,只需要按照他的說明一步一步來就行了(吧)!
結果證明事情果然不是我想的這麼簡單,不管怎麼弄就是跳出209 invalid session token,花了一段時間後找到parse.com自己發的文章Session Migration Tutorial,才知道把這個選項關掉就行了,我花了這麼久到底在幹麻!
總之,關閉這個選項後就成功了,parse.com的資料庫也會成功紀錄登入過的使用者,事情完成一半,其餘的就是登入的使用者資料該怎麼讀取出來了~
UPDATE:使用parse.com Cloud Code Hosting進行Facebook登入存取 - 2
UPDATE:在GitHub上新增了範例程式:demo, GitHub
2012年9月24日 星期一
PHPWord 中文字顯示與下載問題
好久沒有更新了,看到上次更新的日期,我覺得我的文章產出可能會是一年一篇至兩篇(崩潰)
這次碰上的問題主要是有個網頁委託內容包含需動態產生word檔以供使用者下載,因此我從先前接觸過的PHPExcel而找到PHPWord這套library。先前使用PHPExcel時多半是為了利用簡單的方式來讀取excel檔中的內容,而並未自行產出一個獨立的excel檔,而這次算是剛好反過來了,要利用已有的內容來產生一個word檔。
起初利用PHPWord 0.6.2-1 Beta所提供的examples成功建立word檔後覺得還蠻放心的,後來隨即也想到若是包含中文字時會不會有編碼問題,因此測了一下,果然變成亂碼了。後來隨即在官方討論區找到此篇文章:how to properly handle UTF-8 ? (UTF8) ,原來不只我遇到了這個問題~而根據底下的回覆表示以簡體中文編碼為例,須將source code中的$givenText = utf8_encode($text);註解並換成$text = iconv('gbk','utf-8','福建省泉州市惠南工业区北一路');即可解決問題,但這個方法只適用於範例中的Template.php才行,用在Basic Table.php則會出現亂碼。
後來我將source code中所有包含utf8_encode的文件都以iconv的方式去取代,結果算是成功沒出現亂碼了,但是word會在開啟時跳出錯誤警告,表示此檔案已損毀是否要進行修復(修復後沒大礙就是了)。憑著吹毛求疵斤斤計較的精神,也擔心使用者若看到損毀時會有疑慮,因此我又開始找其他方式去做,而最後找到的方法就是直接將有包含utf8_encode的文件都註解掉,改成直接賦予對應值,如下範例:
另外範例中用來產生word的php也記得先改成utf-8,之後即可輕鬆產生包含中文內容的docx檔~
至於該如何直接產生word供使用者一點擊就下載,方法我也都找到了,只是Template在PHPWord中的寫法與其他比較不一樣,因此方法也有被侷限住,一般的如Basic Table可以用以下方法來達到不存檔而下載,只要在最後Save File部分動一點手腳即可:
而Template無法使用上述方法,須使用下面範例才行:
到這裡我所需要的功能大致上齊全了,只剩下PHPWord沒辦法產生word2003(*.doc)的檔案,也是一個令人頭痛的問題。
這次碰上的問題主要是有個網頁委託內容包含需動態產生word檔以供使用者下載,因此我從先前接觸過的PHPExcel而找到PHPWord這套library。先前使用PHPExcel時多半是為了利用簡單的方式來讀取excel檔中的內容,而並未自行產出一個獨立的excel檔,而這次算是剛好反過來了,要利用已有的內容來產生一個word檔。
起初利用PHPWord 0.6.2-1 Beta所提供的examples成功建立word檔後覺得還蠻放心的,後來隨即也想到若是包含中文字時會不會有編碼問題,因此測了一下,果然變成亂碼了。後來隨即在官方討論區找到此篇文章:how to properly handle UTF-8 ? (UTF8) ,原來不只我遇到了這個問題~而根據底下的回覆表示以簡體中文編碼為例,須將source code中的$givenText = utf8_encode($text);註解並換成$text = iconv('gbk','utf-8','福建省泉州市惠南工业区北一路');即可解決問題,但這個方法只適用於範例中的Template.php才行,用在Basic Table.php則會出現亂碼。
// 原始寫法 $givenText = utf8_encode($text); // 修改後 //$givenText = utf8_encode($text); $text = iconv('gbk','utf-8','福建省泉州市惠南工业区北一路');
後來我將source code中所有包含utf8_encode的文件都以iconv的方式去取代,結果算是成功沒出現亂碼了,但是word會在開啟時跳出錯誤警告,表示此檔案已損毀是否要進行修復(修復後沒大礙就是了)。憑著吹毛求疵斤斤計較的精神,也擔心使用者若看到損毀時會有疑慮,因此我又開始找其他方式去做,而最後找到的方法就是直接將有包含utf8_encode的文件都註解掉,改成直接賦予對應值,如下範例:
// 原始寫法 $givenText = utf8_encode($text); // 修改後 //$givenText = utf8_encode($text); $givenText = $text;
另外範例中用來產生word的php也記得先改成utf-8,之後即可輕鬆產生包含中文內容的docx檔~
至於該如何直接產生word供使用者一點擊就下載,方法我也都找到了,只是Template在PHPWord中的寫法與其他比較不一樣,因此方法也有被侷限住,一般的如Basic Table可以用以下方法來達到不存檔而下載,只要在最後Save File部分動一點手腳即可:
// Save File $objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007'); // 原本是儲存到當前目錄下,名為BasicTable.docx // $objWriter->save('BasicTable.docx'); // 先寫入header,再利用$objWriter->save('php://output'); // 將結果直接show出來,即可成功進行下載動作 $filename = 'abc.docx'; header("Cache-Control: public"); header("Content-Description: File Transfer"); header("Content-Disposition: attachment; filename=$filename"); header("Content-Type: application/octet-stream; "); header("Content-Transfer-Encoding: binary"); $objWriter->save('php://output');
而Template無法使用上述方法,須使用下面範例才行:
// Save File // 原本是儲存到當前目錄下,名為Solarsystem.docx // $document->save('Solarsystem.docx'); // 先將檔案暫存起來 $temp_file = tempnam(sys_get_temp_dir(), 'PHPWord'); $document->save($temp_file); // 一樣是寫入header,但最後以不同指令呈現出來,最後再刪掉伺服器上的暫存檔 $objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007'); $filename = 'abc.docx'; header("Cache-Control: public"); header("Content-Description: File Transfer"); header("Content-Disposition: attachment; filename=$filename"); header("Content-Type: application/octet-stream; "); header("Content-Transfer-Encoding: binary"); readfile($temp_file); // or echo file_get_contents($temp_file); unlink($temp_file); // remove temp file
到這裡我所需要的功能大致上齊全了,只剩下PHPWord沒辦法產生word2003(*.doc)的檔案,也是一個令人頭痛的問題。
2011年12月6日 星期二
在Blogger上替程式碼上色
最近開始有想將自己所學、所找到的資訊分享到網路上的念頭,幫助別人也為自己作個筆記。
工欲善其事,必先利其器。在尋找程式相關的文章時,最喜歡看到程式碼有上色及排版的,方便閱讀也能有效提升理解速度。我也希望自己未來所寫的內容也有同樣的效果,於是就開始研究起如何將程式碼上色,而我找到的是Syntax Highlighter。
訂閱:
文章 (Atom)