qqoauth.class.php 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783
  1. <?php
  2. /*
  3. * qq微博APP 接口类
  4. * Code based on:
  5. * Abraham Williams (abraham@abrah.am) http://abrah.am
  6. */
  7. /* Load OAuth lib. You can find it at http://oauth.net */
  8. /**
  9. * @ignore
  10. */
  11. class OAuthException extends Exception {
  12. // pass
  13. }
  14. /**
  15. * @ignore
  16. */
  17. class OAuthConsumer {
  18. public $key;
  19. public $secret;
  20. function __construct($key, $secret) {
  21. $this->key = $key;
  22. $this->secret = $secret;
  23. }
  24. function __toString() {
  25. return "OAuthConsumer[key=$this->key,secret=$this->secret]";
  26. }
  27. }
  28. /**
  29. * @ignore
  30. */
  31. class OAuthToken {
  32. // access tokens and request tokens
  33. public $key;
  34. public $secret;
  35. /**
  36. * key = the token
  37. * secret = the token secret
  38. */
  39. function __construct($key, $secret) {
  40. $this->key = $key;
  41. $this->secret = $secret;
  42. }
  43. /**
  44. * generates the basic string serialization of a token that a server
  45. * would respond to request_token and access_token calls with
  46. */
  47. function to_string() {
  48. return "oauth_token=" .
  49. OAuthUtil::urlencode_rfc3986($this->key) .
  50. "&oauth_token_secret=" .
  51. OAuthUtil::urlencode_rfc3986($this->secret);
  52. }
  53. function __toString() {
  54. return $this->to_string();
  55. }
  56. }
  57. /**
  58. * @ignore
  59. */
  60. class OAuthSignatureMethod {
  61. public function check_signature(&$request, $consumer, $token, $signature) {
  62. $built = $this->build_signature($request, $consumer, $token);
  63. return $built == $signature;
  64. }
  65. }
  66. /**
  67. * @ignore
  68. */
  69. class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
  70. function get_name() {
  71. return "HMAC-SHA1";
  72. }
  73. public function build_signature($request, $consumer, $token) {
  74. $base_string = $request->get_signature_base_string();
  75. //print_r( $base_string );
  76. $request->base_string = $base_string;
  77. $key_parts = array(
  78. $consumer->secret,
  79. ($token) ? $token->secret : ""
  80. );
  81. //print_r( $key_parts );
  82. $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
  83. $key = implode('&', $key_parts);
  84. return base64_encode(hash_hmac('sha1', $base_string, $key, true));
  85. }
  86. }
  87. /**
  88. * @ignore
  89. */
  90. class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
  91. public function get_name() {
  92. return "PLAINTEXT";
  93. }
  94. public function build_signature($request, $consumer, $token) {
  95. $sig = array(
  96. OAuthUtil::urlencode_rfc3986($consumer->secret)
  97. );
  98. if ($token) {
  99. array_push($sig, OAuthUtil::urlencode_rfc3986($token->secret));
  100. } else {
  101. array_push($sig, '');
  102. }
  103. $raw = implode("&", $sig);
  104. // for debug purposes
  105. $request->base_string = $raw;
  106. return OAuthUtil::urlencode_rfc3986($raw);
  107. }
  108. }
  109. /**
  110. * @ignore
  111. */
  112. class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
  113. public function get_name() {
  114. return "RSA-SHA1";
  115. }
  116. protected function fetch_public_cert(&$request) {
  117. // not implemented yet, ideas are:
  118. // (1) do a lookup in a table of trusted certs keyed off of consumer
  119. // (2) fetch via http using a url provided by the requester
  120. // (3) some sort of specific discovery code based on request
  121. //
  122. // either way should return a string representation of the certificate
  123. throw Exception("fetch_public_cert not implemented");
  124. }
  125. protected function fetch_private_cert(&$request) {
  126. // not implemented yet, ideas are:
  127. // (1) do a lookup in a table of trusted certs keyed off of consumer
  128. //
  129. // either way should return a string representation of the certificate
  130. throw Exception("fetch_private_cert not implemented");
  131. }
  132. public function build_signature(&$request, $consumer, $token) {
  133. $base_string = $request->get_signature_base_string();
  134. $request->base_string = $base_string;
  135. // Fetch the private key cert based on the request
  136. $cert = $this->fetch_private_cert($request);
  137. // Pull the private key ID from the certificate
  138. $privatekeyid = openssl_get_privatekey($cert);
  139. // Sign using the key
  140. $ok = openssl_sign($base_string, $signature, $privatekeyid);
  141. // Release the key resource
  142. openssl_free_key($privatekeyid);
  143. return base64_encode($signature);
  144. }
  145. public function check_signature(&$request, $consumer, $token, $signature) {
  146. $decoded_sig = base64_decode($signature);
  147. $base_string = $request->get_signature_base_string();
  148. // Fetch the public key cert based on the request
  149. $cert = $this->fetch_public_cert($request);
  150. // Pull the public key ID from the certificate
  151. $publickeyid = openssl_get_publickey($cert);
  152. // Check the computed signature against the one passed in the query
  153. $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
  154. // Release the key resource
  155. openssl_free_key($publickeyid);
  156. return $ok == 1;
  157. }
  158. }
  159. /**
  160. * @ignore
  161. */
  162. class OAuthRequest {
  163. private $parameters;
  164. private $http_method;
  165. private $http_url;
  166. // for debug purposes
  167. public $base_string;
  168. public static $version = '1.0a';
  169. public static $POST_INPUT = 'php://input';
  170. function __construct($http_method, $http_url, $parameters=NULL) {
  171. @$parameters or $parameters = array();
  172. $this->parameters = $parameters;
  173. $this->http_method = $http_method;
  174. $this->http_url = $http_url;
  175. }
  176. /**
  177. * attempt to build up a request from what was passed to the server
  178. */
  179. public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
  180. $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
  181. ? 'http'
  182. : 'https';
  183. @$http_url or $http_url = $scheme .
  184. '://' . $_SERVER['HTTP_HOST'] .
  185. ':' .
  186. $_SERVER['SERVER_PORT'] .
  187. $_SERVER['REQUEST_URI'];
  188. @$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
  189. // We weren't handed any parameters, so let's find the ones relevant to
  190. // this request.
  191. // If you run XML-RPC or similar you should use this to provide your own
  192. // parsed parameter-list
  193. if (!$parameters) {
  194. // Find request headers
  195. $request_headers = OAuthUtil::get_headers();
  196. // Parse the query-string to find GET parameters
  197. $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
  198. // It's a POST request of the proper content-type, so parse POST
  199. // parameters and add those overriding any duplicates from GET
  200. if ($http_method == "POST"
  201. && @strstr($request_headers["Content-Type"],
  202. "application/x-www-form-urlencoded")
  203. ) {
  204. $post_data = OAuthUtil::parse_parameters(
  205. file_get_contents(self::$POST_INPUT)
  206. );
  207. $parameters = array_merge($parameters, $post_data);
  208. }
  209. // We have a Authorization-header with OAuth data. Parse the header
  210. // and add those overriding any duplicates from GET or POST
  211. if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
  212. $header_parameters = OAuthUtil::split_header(
  213. $request_headers['Authorization']
  214. );
  215. $parameters = array_merge($parameters, $header_parameters);
  216. }
  217. }
  218. return new OAuthRequest($http_method, $http_url, $parameters);
  219. }
  220. /**
  221. * pretty much a helper function to set up the request
  222. */
  223. public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
  224. @$parameters or $parameters = array();
  225. $defaults = array("oauth_version" => OAuthRequest::$version,
  226. "oauth_nonce" => OAuthRequest::generate_nonce(),
  227. "oauth_timestamp" => OAuthRequest::generate_timestamp(),
  228. "oauth_consumer_key" => $consumer->key);
  229. if ($token)
  230. $defaults['oauth_token'] = $token->key;
  231. $parameters = array_merge($defaults, $parameters);
  232. return new OAuthRequest($http_method, $http_url, $parameters);
  233. }
  234. public function set_parameter($name, $value, $allow_duplicates = true) {
  235. if ($allow_duplicates && isset($this->parameters[$name])) {
  236. // We have already added parameter(s) with this name, so add to the list
  237. if (is_scalar($this->parameters[$name])) {
  238. // This is the first duplicate, so transform scalar (string)
  239. // into an array so we can add the duplicates
  240. $this->parameters[$name] = array($this->parameters[$name]);
  241. }
  242. $this->parameters[$name][] = $value;
  243. } else {
  244. $this->parameters[$name] = $value;
  245. }
  246. }
  247. public function get_parameter($name) {
  248. return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
  249. }
  250. public function get_parameters() {
  251. return $this->parameters;
  252. }
  253. public function unset_parameter($name) {
  254. unset($this->parameters[$name]);
  255. }
  256. /**
  257. * The request parameters, sorted and concatenated into a normalized string.
  258. * @return string
  259. */
  260. public function get_signable_parameters() {
  261. // Grab all parameters
  262. $params = $this->parameters;
  263. // remove pic
  264. if (isset($params['pic'])) {
  265. unset($params['pic']);
  266. }
  267. if (isset($params['image']))
  268. {
  269. unset($params['image']);
  270. }
  271. // Remove oauth_signature if present
  272. // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
  273. if (isset($params['oauth_signature'])) {
  274. unset($params['oauth_signature']);
  275. }
  276. return OAuthUtil::build_http_query($params);
  277. }
  278. /**
  279. * Returns the base string of this request
  280. *
  281. * The base string defined as the method, the url
  282. * and the parameters (normalized), each urlencoded
  283. * and the concated with &.
  284. */
  285. public function get_signature_base_string() {
  286. $parts = array(
  287. $this->get_normalized_http_method(),
  288. $this->get_normalized_http_url(),
  289. $this->get_signable_parameters()
  290. );
  291. //print_r( $parts );
  292. $parts = OAuthUtil::urlencode_rfc3986($parts);
  293. return implode('&', $parts);
  294. }
  295. /**
  296. * just uppercases the http method
  297. */
  298. public function get_normalized_http_method() {
  299. return strtoupper($this->http_method);
  300. }
  301. /**
  302. * parses the url and rebuilds it to be
  303. * scheme://host/path
  304. */
  305. public function get_normalized_http_url() {
  306. $parts = parse_url($this->http_url);
  307. $port = @$parts['port'];
  308. $scheme = $parts['scheme'];
  309. $host = $parts['host'];
  310. $path = @$parts['path'];
  311. $port or $port = ($scheme == 'https') ? '443' : '80';
  312. if (($scheme == 'https' && $port != '443')
  313. || ($scheme == 'http' && $port != '80')) {
  314. $host = "$host:$port";
  315. }
  316. return "$scheme://$host$path";
  317. }
  318. /**
  319. * builds a url usable for a GET request
  320. */
  321. public function to_url() {
  322. $post_data = $this->to_postdata();
  323. $out = $this->get_normalized_http_url();
  324. if ($post_data) {
  325. $out .= '?'.$post_data;
  326. }
  327. return $out;
  328. }
  329. /**
  330. * builds the data one would send in a POST request
  331. */
  332. public function to_postdata( $multi = false ) {
  333. //echo "multi=" . $multi . '`';
  334. if( $multi )
  335. return OAuthUtil::build_http_query_multi($this->parameters);
  336. else
  337. return OAuthUtil::build_http_query($this->parameters);
  338. }
  339. /**
  340. * builds the Authorization: header
  341. */
  342. public function to_header() {
  343. $out ='Authorization: OAuth realm=""';
  344. $total = array();
  345. foreach ($this->parameters as $k => $v) {
  346. if (substr($k, 0, 5) != "oauth") continue;
  347. if (is_array($v)) {
  348. throw new OAuthException('Arrays not supported in headers');
  349. }
  350. $out .= ',' .
  351. OAuthUtil::urlencode_rfc3986($k) .
  352. '="' .
  353. OAuthUtil::urlencode_rfc3986($v) .
  354. '"';
  355. }
  356. return $out;
  357. }
  358. public function __toString() {
  359. return $this->to_url();
  360. }
  361. public function sign_request($signature_method, $consumer, $token) {
  362. $this->set_parameter(
  363. "oauth_signature_method",
  364. $signature_method->get_name(),
  365. false
  366. );
  367. $signature = $this->build_signature($signature_method, $consumer, $token);
  368. //echo "sign=" . $signature;
  369. $this->set_parameter("oauth_signature", $signature, false);
  370. }
  371. public function build_signature($signature_method, $consumer, $token) {
  372. $signature = $signature_method->build_signature($this, $consumer, $token);
  373. return $signature;
  374. }
  375. /**
  376. * util function: current timestamp
  377. */
  378. private static function generate_timestamp() {
  379. //return 1273566716;
  380. //echo date("y-m-d H:i:s");
  381. return time();
  382. }
  383. /**
  384. * util function: current nonce
  385. */
  386. private static function generate_nonce() {
  387. //return '462d316f6f40c40a9e0eef1b009f37fa';
  388. $mt = microtime();
  389. $rand = mt_rand();
  390. return md5($mt . $rand); // md5s look nicer than numbers
  391. }
  392. }
  393. /**
  394. * @ignore
  395. */
  396. class OAuthServer {
  397. protected $timestamp_threshold = 300; // in seconds, five minutes
  398. protected $version = 1.0; // hi blaine
  399. protected $signature_methods = array();
  400. protected $data_store;
  401. function __construct($data_store) {
  402. $this->data_store = $data_store;
  403. }
  404. public function add_signature_method($signature_method) {
  405. $this->signature_methods[$signature_method->get_name()] =
  406. $signature_method;
  407. }
  408. // high level functions
  409. /**
  410. * process a request_token request
  411. * returns the request token on success
  412. */
  413. public function fetch_request_token(&$request) {
  414. $this->get_version($request);
  415. $consumer = $this->get_consumer($request);
  416. // no token required for the initial token request
  417. $token = NULL;
  418. $this->check_signature($request, $consumer, $token);
  419. $new_token = $this->data_store->new_request_token($consumer);
  420. return $new_token;
  421. }
  422. /**
  423. * process an access_token request
  424. * returns the access token on success
  425. */
  426. public function fetch_access_token(&$request) {
  427. $this->get_version($request);
  428. $consumer = $this->get_consumer($request);
  429. // requires authorized request token
  430. $token = $this->get_token($request, $consumer, "request");
  431. $this->check_signature($request, $consumer, $token);
  432. $new_token = $this->data_store->new_access_token($token, $consumer);
  433. return $new_token;
  434. }
  435. /**
  436. * verify an api call, checks all the parameters
  437. */
  438. public function verify_request(&$request) {
  439. $this->get_version($request);
  440. $consumer = $this->get_consumer($request);
  441. $token = $this->get_token($request, $consumer, "access");
  442. $this->check_signature($request, $consumer, $token);
  443. return array($consumer, $token);
  444. }
  445. // Internals from here
  446. /**
  447. * version 1
  448. */
  449. private function get_version(&$request) {
  450. $version = $request->get_parameter("oauth_version");
  451. if (!$version) {
  452. $version = 1.0;
  453. }
  454. if ($version && $version != $this->version) {
  455. throw new OAuthException("OAuth version '$version' not supported");
  456. }
  457. return $version;
  458. }
  459. /**
  460. * figure out the signature with some defaults
  461. */
  462. private function get_signature_method(&$request) {
  463. $signature_method =
  464. @$request->get_parameter("oauth_signature_method");
  465. if (!$signature_method) {
  466. $signature_method = "PLAINTEXT";
  467. }
  468. if (!in_array($signature_method,
  469. array_keys($this->signature_methods))) {
  470. throw new OAuthException(
  471. "Signature method '$signature_method' not supported " .
  472. "try one of the following: " .
  473. implode(", ", array_keys($this->signature_methods))
  474. );
  475. }
  476. return $this->signature_methods[$signature_method];
  477. }
  478. /**
  479. * try to find the consumer for the provided request's consumer key
  480. */
  481. private function get_consumer(&$request) {
  482. $consumer_key = @$request->get_parameter("oauth_consumer_key");
  483. if (!$consumer_key) {
  484. throw new OAuthException("Invalid consumer key");
  485. }
  486. $consumer = $this->data_store->lookup_consumer($consumer_key);
  487. if (!$consumer) {
  488. throw new OAuthException("Invalid consumer");
  489. }
  490. return $consumer;
  491. }
  492. /**
  493. * try to find the token for the provided request's token key
  494. */
  495. private function get_token(&$request, $consumer, $token_type="access") {
  496. $token_field = @$request->get_parameter('oauth_token');
  497. $token = $this->data_store->lookup_token(
  498. $consumer, $token_type, $token_field
  499. );
  500. if (!$token) {
  501. throw new OAuthException("Invalid $token_type token: $token_field");
  502. }
  503. return $token;
  504. }
  505. /**
  506. * all-in-one function to check the signature on a request
  507. * should guess the signature method appropriately
  508. */
  509. private function check_signature(&$request, $consumer, $token) {
  510. // this should probably be in a different method
  511. $timestamp = @$request->get_parameter('oauth_timestamp');
  512. $nonce = @$request->get_parameter('oauth_nonce');
  513. $this->check_timestamp($timestamp);
  514. $this->check_nonce($consumer, $token, $nonce, $timestamp);
  515. $signature_method = $this->get_signature_method($request);
  516. $signature = $request->get_parameter('oauth_signature');
  517. $valid_sig = $signature_method->check_signature(
  518. $request,
  519. $consumer,
  520. $token,
  521. $signature
  522. );
  523. if (!$valid_sig) {
  524. throw new OAuthException("Invalid signature");
  525. }
  526. }
  527. /**
  528. * check that the timestamp is new enough
  529. */
  530. private function check_timestamp($timestamp) {
  531. // verify that timestamp is recentish
  532. $now = time();
  533. if ($now - $timestamp > $this->timestamp_threshold) {
  534. throw new OAuthException(
  535. "Expired timestamp, yours $timestamp, ours $now"
  536. );
  537. }
  538. }
  539. /**
  540. * check that the nonce is not repeated
  541. */
  542. private function check_nonce($consumer, $token, $nonce, $timestamp) {
  543. // verify that the nonce is uniqueish
  544. $found = $this->data_store->lookup_nonce(
  545. $consumer,
  546. $token,
  547. $nonce,
  548. $timestamp
  549. );
  550. if ($found) {
  551. throw new OAuthException("Nonce already used: $nonce");
  552. }
  553. }
  554. }
  555. /**
  556. * @ignore
  557. */
  558. class OAuthDataStore {
  559. function lookup_consumer($consumer_key) {
  560. // implement me
  561. }
  562. function lookup_token($consumer, $token_type, $token) {
  563. // implement me
  564. }
  565. function lookup_nonce($consumer, $token, $nonce, $timestamp) {
  566. // implement me
  567. }
  568. function new_request_token($consumer) {
  569. // return a new token attached to this consumer
  570. }
  571. function new_access_token($token, $consumer) {
  572. // return a new access token attached to this consumer
  573. // for the user associated with this token if the request token
  574. // is authorized
  575. // should also invalidate the request token
  576. }
  577. }
  578. /**
  579. * @ignore
  580. */
  581. class OAuthUtil {
  582. public static $boundary = '';
  583. public static function urlencode_rfc3986($input) {
  584. if (is_array($input)) {
  585. return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
  586. } else if (is_scalar($input)) {
  587. return str_replace(
  588. '+',
  589. ' ',
  590. str_replace('%7E', '~', rawurlencode($input))
  591. );
  592. } else {
  593. return '';
  594. }
  595. }
  596. // This decode function isn't taking into consideration the above
  597. // modifications to the encoding process. However, this method doesn't
  598. // seem to be used anywhere so leaving it as is.
  599. public static function urldecode_rfc3986($string) {
  600. return urldecode($string);
  601. }
  602. // Utility function for turning the Authorization: header into
  603. // parameters, has to do some unescaping
  604. // Can filter out any non-oauth parameters if needed (default behaviour)
  605. public static function split_header($header, $only_allow_oauth_parameters = true) {
  606. $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
  607. $offset = 0;
  608. $params = array();
  609. while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
  610. $match = $matches[0];
  611. $header_name = $matches[2][0];
  612. $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0];
  613. if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) {
  614. $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content);
  615. }
  616. $offset = $match[1] + strlen($match[0]);
  617. }
  618. if (isset($params['realm'])) {
  619. unset($params['realm']);
  620. }
  621. return $params;
  622. }
  623. // helper to try to sort out headers for people who aren't running apache
  624. public static function get_headers() {
  625. if (function_exists('apache_request_headers')) {
  626. // we need this to get the actual Authorization: header
  627. // because apache tends to tell us it doesn't exist
  628. return apache_request_headers();
  629. }
  630. // otherwise we don't have apache and are just going to have to hope
  631. // that $_SERVER actually contains what we need
  632. $out = array();
  633. foreach ($_SERVER as $key => $value) {
  634. if (substr($key, 0, 5) == "HTTP_") {
  635. // this is chaos, basically it is just there to capitalize the first
  636. // letter of every word that is not an initial HTTP and strip HTTP
  637. // code from przemek
  638. $key = str_replace(
  639. " ",
  640. "-",
  641. ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
  642. );
  643. $out[$key] = $value;
  644. }
  645. }
  646. return $out;
  647. }
  648. // This function takes a input like a=b&a=c&d=e and returns the parsed
  649. // parameters like this
  650. // array('a' => array('b','c'), 'd' => 'e')
  651. public static function parse_parameters( $input ) {
  652. if (!isset($input) || !$input) return array();
  653. $pairs = explode('&', $input);
  654. $parsed_parameters = array();
  655. foreach ($pairs as $pair) {
  656. $split = explode('=', $pair, 2);
  657. $parameter = OAuthUtil::urldecode_rfc3986($split[0]);
  658. $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : '';
  659. if (isset($parsed_parameters[$parameter])) {
  660. // We have already recieved parameter(s) with this name, so add to the list
  661. // of parameters with this name
  662. if (is_scalar($parsed_parameters[$parameter])) {
  663. // This is the first duplicate, so transform scalar (string) into an array
  664. // so we can add the duplicates
  665. $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
  666. }
  667. $parsed_parameters[$parameter][] = $value;
  668. } else {
  669. $parsed_parameters[$parameter] = $value;
  670. }
  671. }
  672. return $parsed_parameters;
  673. }
  674. public static function build_http_query_multi($params) {
  675. if (!$params) return '';
  676. //print_r( $params );
  677. //return null;
  678. // Urlencode both keys and values
  679. $keys = array_keys($params);
  680. $values = array_values($params);
  681. //$keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
  682. //$values = OAuthUtil::urlencode_rfc3986(array_values($params));
  683. $params = array_combine($keys, $values);
  684. // Parameters are sorted by name, using lexicographical byte value ordering.
  685. // Ref: Spec: 9.1.1 (1)
  686. uksort($params, 'strcmp');
  687. $pairs = array();
  688. self::$boundary = $boundary = uniqid('------------------');
  689. $MPboundary = '--'.$boundary;
  690. $endMPboundary = $MPboundary. '--';
  691. $multipartbody = '';
  692. foreach ($params as $parameter => $value) {
  693. //if( $parameter == 'pic' && $value{0} == '@' )
  694. if( in_array($parameter,array("pic","image")) && $value{0} == '@' )
  695. {
  696. $url = ltrim( $value , '@' );
  697. $content = file_get_contents( $url );
  698. $filename = reset( explode( '?' , basename( $url ) ));
  699. $mime = self::get_image_mime($url);
  700. $multipartbody .= $MPboundary . "\r\n";
  701. $multipartbody .= 'Content-Disposition: form-data; name="' . $parameter . '"; filename="' . $filename . '"'. "\r\n";
  702. $multipartbody .= 'Content-Type: '. $mime . "\r\n\r\n";
  703. $multipartbody .= $content. "\r\n";
  704. }
  705. else
  706. {
  707. $multipartbody .= $MPboundary . "\r\n";
  708. $multipartbody .= 'content-disposition: form-data; name="'.$parameter."\"\r\n\r\n";
  709. $multipartbody .= $value."\r\n";
  710. }
  711. }
  712. $multipartbody .= $endMPboundary;
  713. // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
  714. // Each name-value pair is separated by an '&' character (ASCII code 38)
  715. // echo $multipartbody;
  716. return $multipartbody;
  717. }
  718. public static function build_http_query($params) {
  719. if (!$params) return '';
  720. // Urlencode both keys and values
  721. $keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
  722. $values = OAuthUtil::urlencode_rfc3986(array_values($params));
  723. $params = array_combine($keys, $values);
  724. // Parameters are sorted by name, using lexicographical byte value ordering.
  725. // Ref: Spec: 9.1.1 (1)
  726. uksort($params, 'strcmp');
  727. $pairs = array();
  728. foreach ($params as $parameter => $value) {
  729. if (is_array($value)) {
  730. // If two or more parameters share the same name, they are sorted by their value
  731. // Ref: Spec: 9.1.1 (1)
  732. natsort($value);
  733. foreach ($value as $duplicate_value) {
  734. $pairs[] = $parameter . '=' . $duplicate_value;
  735. }
  736. } else {
  737. $pairs[] = $parameter . '=' . $value;
  738. }
  739. }
  740. // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
  741. // Each name-value pair is separated by an '&' character (ASCII code 38)
  742. return implode('&', $pairs);
  743. }
  744. public static function get_image_mime( $file )
  745. {
  746. $ext = strtolower(pathinfo( $file , PATHINFO_EXTENSION ));
  747. switch( $ext )
  748. {
  749. case 'jpg':
  750. case 'jpeg':
  751. $mime = 'image/jpg';
  752. break;
  753. case 'png';
  754. $mime = 'image/png';
  755. break;
  756. case 'gif';
  757. default:
  758. $mime = 'image/gif';
  759. break;
  760. }
  761. return $mime;
  762. }
  763. }
  764. /**
  765. * qq微博操作类
  766. *
  767. * @package sae
  768. * @author Easy Chen
  769. * @version 1.0
  770. */
  771. class WeiboClient
  772. {
  773. /**
  774. * 构造函数
  775. *
  776. * @access public
  777. * @param mixed $akey 微博开放平台应用APP KEY
  778. * @param mixed $skey 微博开放平台应用APP SECRET
  779. * @param mixed $accecss_token OAuth认证返回的token
  780. * @param mixed $accecss_token_secret OAuth认证返回的token secret
  781. * @return void
  782. */
  783. function __construct( $akey , $skey , $accecss_token , $accecss_token_secret )
  784. {
  785. $this->oauth = new WeiboOAuth( $akey , $skey , $accecss_token , $accecss_token_secret );
  786. }
  787. /**
  788. * 最新公共微博
  789. *
  790. * @access public
  791. * @return array
  792. */
  793. function public_timeline()
  794. {
  795. return $this->oauth->get('http://open.t.qq.com/api/statuses/home_timeline');
  796. }
  797. /**
  798. * 最新关注人微博
  799. *
  800. * @access public
  801. * @return array
  802. */
  803. function friends_timeline()
  804. {
  805. return $this->home_timeline();
  806. }
  807. /**
  808. * 最新关注人微博
  809. *
  810. * @access public
  811. * @return array
  812. */
  813. function home_timeline()
  814. {
  815. return $this->oauth->get('http://open.t.qq.com/api/statuses/home_timeline.json');
  816. }
  817. /**
  818. * 最新 @用户的
  819. *
  820. * @access public
  821. * @param int $page 返回结果的页序号。
  822. * @param int $count 每次返回的最大记录数(即页面大小),不大于200,默认为20。
  823. * @return array
  824. */
  825. function mentions( $page = 1 , $count = 20 )
  826. {
  827. return $this->request_with_pager( 'http://open.t.qq.com/api/statuses/mentions.json' , $page , $count );
  828. }
  829. /**
  830. * 发表微博
  831. *
  832. * @access public
  833. * @param mixed $text 要更新的微博信息。
  834. * @return array
  835. */
  836. function update( $text )
  837. {
  838. // http://open.t.qq.com/api/statuses/update.json
  839. $param = array();
  840. $param['status'] = $text;
  841. return $this->oauth->post( 'http://open.t.qq.com/api/statuses/update.json' , $param );
  842. }
  843. /**
  844. * 发表图片微博
  845. *
  846. * @access public
  847. * @param string $text 要更新的微博信息。
  848. * @param string $text 要发布的图片路径,支持url。[只支持png/jpg/gif三种格式,增加格式请修改get_image_mime方法]
  849. * @return array
  850. */
  851. function upload( $text , $pic_path )
  852. {
  853. // http://open.t.qq.com/api/statuses/update.json
  854. $param = array();
  855. $param['status'] = $text;
  856. $param['pic'] = '@'.$pic_path;
  857. return $this->oauth->post( 'http://open.t.qq.com/api/statuses/upload.json' , $param , true );
  858. }
  859. /**
  860. * 获取单条微博
  861. *
  862. * @access public
  863. * @param mixed $sid 要获取已发表的微博ID
  864. * @return array
  865. */
  866. function show_status( $sid )
  867. {
  868. return $this->oauth->get( 'http://open.t.qq.com/api/statuses/show/' . $sid . '.json' );
  869. }
  870. /**
  871. * 删除微博
  872. *
  873. * @access public
  874. * @param mixed $sid 要删除的微博ID
  875. * @return array
  876. */
  877. function delete( $sid )
  878. {
  879. return $this->destroy( $sid );
  880. }
  881. /**
  882. * 删除微博
  883. *
  884. * @access public
  885. * @param mixed $sid 要删除的微博ID
  886. * @return array
  887. */
  888. function destroy( $sid )
  889. {
  890. return $this->oauth->post( 'http://open.t.qq.com/api/statuses/destroy/' . $sid . '.json' );
  891. }
  892. /**
  893. * 个人资料
  894. *
  895. * @access public
  896. * @param mixed $uid_or_name 用户UID或微博昵称。
  897. * @return array
  898. */
  899. function show_user( $uid_or_name = null )
  900. {
  901. return $this->request_with_uid( 'http://open.t.qq.com/api/users/show.json' , $uid_or_name );
  902. }
  903. /**
  904. * 关注人列表
  905. *
  906. * @access public
  907. * @param bool $cursor 单页只能包含100个关注列表,为了获取更多则cursor默认从-1开始,通过增加或减少cursor来获取更多的关注列表
  908. * @param bool $count 每次返回的最大记录数(即页面大小),不大于200,默认返回20
  909. * @param mixed $uid_or_name 要获取的 UID或微博昵称
  910. * @return array
  911. */
  912. function friends( $cursor = false , $count = false , $uid_or_name = null )
  913. {
  914. return $this->request_with_uid( 'http://open.t.qq.com/api/statuses/friends.json' , $uid_or_name , false , $count , $cursor );
  915. }
  916. /**
  917. * 粉丝列表
  918. *
  919. * @access public
  920. * @param bool $cursor 单页只能包含100个粉丝列表,为了获取更多则cursor默认从-1开始,通过增加或减少cursor来获取更多的粉丝列表
  921. * @param bool $count 每次返回的最大记录数(即页面大小),不大于200,默认返回20。
  922. * @param mixed $uid_or_name 要获取的 UID或微博昵称
  923. * @return array
  924. */
  925. function followers( $cursor = false , $count = false , $uid_or_name = null )
  926. {
  927. return $this->request_with_uid( 'http://open.t.qq.com/api/statuses/followers.json' , $uid_or_name , false , $count , $cursor );
  928. }
  929. /**
  930. * 关注一个用户
  931. *
  932. * @access public
  933. * @param mixed $uid_or_name 要关注的用户UID或微博昵称
  934. * @return array
  935. */
  936. function follow( $uid_or_name )
  937. {
  938. return $this->request_with_uid( 'http://open.t.qq.com/api/friendships/create.json' , $uid_or_name , false , false , false , true );
  939. }
  940. /**
  941. * 取消关注某用户
  942. *
  943. * @access public
  944. * @param mixed $uid_or_name 要取消关注的用户UID或微博昵称
  945. * @return array
  946. */
  947. function unfollow( $uid_or_name )
  948. {
  949. return $this->request_with_uid( 'http://open.t.qq.com/api/friendships/destroy.json' , $uid_or_name , false , false , false , true);
  950. }
  951. /**
  952. * 返回两个用户关系的详细情况
  953. *
  954. * @access public
  955. * @param mixed $uid_or_name 要判断的用户UID
  956. * @return array
  957. */
  958. function is_followed( $uid_or_name )
  959. {
  960. $param = array();
  961. if( is_numeric( $uid_or_name ) ) $param['target_id'] = $uid_or_name;
  962. else $param['target_screen_name'] = $uid_or_name;
  963. return $this->oauth->get( 'http://open.t.qq.com/api/friendships/show.json' , $param );
  964. }
  965. /**
  966. * 用户发表微博列表
  967. *
  968. * @access public
  969. * @param int $page 页码
  970. * @param int $count 每次返回的最大记录数,最多返回200条,默认20。
  971. * @param mixed $uid_or_name 指定用户UID或微博昵称
  972. * @return array
  973. */
  974. function user_timeline( $page = 1 , $count = 20 , $uid_or_name = null )
  975. {
  976. if( !is_numeric( $page ) )
  977. return $this->request_with_uid( 'http://open.t.qq.com/api/statuses/user_timeline.json' , $page );
  978. else
  979. return $this->request_with_uid( 'http://open.t.qq.com/api/statuses/user_timeline.json' , $uid_or_name , $page , $count );
  980. }
  981. /**
  982. * 获取私信列表
  983. *
  984. * @access public
  985. * @param int $page 页码
  986. * @param int $count 每次返回的最大记录数,最多返回200条,默认20。
  987. * @return array
  988. */
  989. function list_dm( $page = 1 , $count = 20 )
  990. {
  991. return $this->request_with_pager( 'http://open.t.qq.com/api/direct_messages.json' , $page , $count );
  992. }
  993. /**
  994. * 发送的私信列表
  995. *
  996. * @access public
  997. * @param int $page 页码
  998. * @param int $count 每次返回的最大记录数,最多返回200条,默认20。
  999. * @return array
  1000. */
  1001. function list_dm_sent( $page = 1 , $count = 20 )
  1002. {
  1003. return $this->request_with_pager( 'http://open.t.qq.com/api/direct_messages/sent.json' , $page , $count );
  1004. }
  1005. /**
  1006. * 发送私信
  1007. *
  1008. * @access public
  1009. * @param mixed $uid_or_name UID或微博昵称
  1010. * @param mixed $text 要发生的消息内容,文本大小必须小于300个汉字。
  1011. * @return array
  1012. */
  1013. function send_dm( $uid_or_name , $text )
  1014. {
  1015. $param = array();
  1016. $param['text'] = $text;
  1017. if( is_numeric( $uid_or_name ) ) $param['user_id'] = $uid_or_name;
  1018. else $param['screen_name'] = $uid_or_name;
  1019. return $this->oauth->post( 'http://open.t.qq.com/api/direct_messages/new.json' , $param );
  1020. }
  1021. /**
  1022. * 删除一条私信
  1023. *
  1024. * @access public
  1025. * @param mixed $did 要删除的私信主键ID
  1026. * @return array
  1027. */
  1028. function delete_dm( $did )
  1029. {
  1030. return $this->oauth->post( 'http://open.t.qq.com/api/direct_messages/destroy/' . $did . '.json' );
  1031. }
  1032. /**
  1033. * 转发一条微博信息。
  1034. *
  1035. * @access public
  1036. * @param mixed $sid 转发的微博ID
  1037. * @param bool $text 添加的转发信息。
  1038. * @return array
  1039. */
  1040. function repost( $sid , $text = false )
  1041. {
  1042. $param = array();
  1043. $param['id'] = $sid;
  1044. if( $text ) $param['status'] = $text;
  1045. return $this->oauth->post( 'http://open.t.qq.com/api/statuses/repost.json' , $param );
  1046. }
  1047. /**
  1048. * 对一条微博信息进行评论
  1049. *
  1050. * @access public
  1051. * @param mixed $sid 要评论的微博id
  1052. * @param mixed $text 评论内容
  1053. * @param bool $cid 要评论的评论id
  1054. * @return array
  1055. */
  1056. function send_comment( $sid , $text , $cid = false )
  1057. {
  1058. $param = array();
  1059. $param['id'] = $sid;
  1060. $param['comment'] = $text;
  1061. if( $cid ) $param['cid '] = $cid;
  1062. return $this->oauth->post( 'http://open.t.qq.com/api/statuses/comment.json' , $param );
  1063. }
  1064. /**
  1065. * 发出的评论
  1066. *
  1067. * @access public
  1068. * @param int $page 页码
  1069. * @param int $count 每次返回的最大记录数,最多返回200条,默认20。
  1070. * @return array
  1071. */
  1072. function comments_by_me( $page = 1 , $count = 20 )
  1073. {
  1074. return $this->request_with_pager( 'http://open.t.qq.com/api/statuses/comments_by_me.json' , $page , $count );
  1075. }
  1076. /**
  1077. * 最新评论(按时间)
  1078. *
  1079. * @access public
  1080. * @param int $page 页码
  1081. * @param int $count 每次返回的最大记录数,最多返回200条,默认20。
  1082. * @return array
  1083. */
  1084. function comments_timeline( $page = 1 , $count = 20 )
  1085. {
  1086. return $this->request_with_pager( 'http://open.t.qq.com/api/statuses/comments_timeline.json' , $page , $count );
  1087. }
  1088. /**
  1089. * 单条评论列表(按微博)
  1090. *
  1091. * @access public
  1092. * @param mixed $sid 指定的微博ID
  1093. * @param int $page 页码
  1094. * @param int $count 每次返回的最大记录数,最多返回200条,默认20。
  1095. * @return array
  1096. */
  1097. function get_comments_by_sid( $sid , $page = 1 , $count = 20 )
  1098. {
  1099. $param = array();
  1100. $param['id'] = $sid;
  1101. if( $page ) $param['page'] = $page;
  1102. if( $count ) $param['count'] = $count;
  1103. return $this->oauth->get('http://open.t.qq.com/api/statuses/comments.json' , $param );
  1104. }
  1105. /**
  1106. * 批量统计微博的评论数,转发数,一次请求最多获取100个。
  1107. *
  1108. * @access public
  1109. * @param mixed $sids 微博ID号列表,用逗号隔开
  1110. * @return array
  1111. */
  1112. function get_count_info_by_ids( $sids )
  1113. {
  1114. $param = array();
  1115. $param['ids'] = $sids;
  1116. return $this->oauth->get( 'http://open.t.qq.com/api/statuses/counts.json' , $param );
  1117. }
  1118. /**
  1119. * 对一条微博评论信息进行回复。
  1120. *
  1121. * @access public
  1122. * @param mixed $sid 微博id
  1123. * @param mixed $text 评论内容。
  1124. * @param mixed $cid 评论id
  1125. * @return array
  1126. */
  1127. function reply( $sid , $text , $cid )
  1128. {
  1129. $param = array();
  1130. $param['id'] = $sid;
  1131. $param['comment'] = $text;
  1132. $param['cid '] = $cid;
  1133. return $this->oauth->post( 'http://open.t.qq.com/api/statuses/reply.json' , $param );
  1134. }
  1135. /**
  1136. * 返回用户的发布的最近20条收藏信息,和用户收藏页面返回内容是一致的。
  1137. *
  1138. * @access public
  1139. * @param bool $page 返回结果的页序号。
  1140. * @return array
  1141. */
  1142. function get_favorites( $page = false )
  1143. {
  1144. $param = array();
  1145. if( $page ) $param['page'] = $page;
  1146. return $this->oauth->get( 'http://open.t.qq.com/api/favorites.json' , $param );
  1147. }
  1148. /**
  1149. * 收藏一条微博信息
  1150. *
  1151. * @access public
  1152. * @param mixed $sid 收藏的微博id
  1153. * @return array
  1154. */
  1155. function add_to_favorites( $sid )
  1156. {
  1157. $param = array();
  1158. $param['id'] = $sid;
  1159. return $this->oauth->post( 'http://open.t.qq.com/api/favorites/create.json' , $param );
  1160. }
  1161. /**
  1162. * 删除微博收藏。
  1163. *
  1164. * @access public
  1165. * @param mixed $sid 要删除的收藏微博信息ID.
  1166. * @return array
  1167. */
  1168. function remove_from_favorites( $sid )
  1169. {
  1170. return $this->oauth->post( 'http://open.t.qq.com/api/favorites/destroy/' . $sid . '.json' );
  1171. }
  1172. function verify_credentials()
  1173. {
  1174. return $this->oauth->get( 'http://open.t.qq.com/api/user/info?format=json' );
  1175. }
  1176. function update_avatar( $pic_path )
  1177. {
  1178. $param = array();
  1179. $param['image'] = "@".$pic_path;
  1180. return $this->oauth->post( 'http://open.t.qq.com/api/account/update_profile_image.json' , $param , true );
  1181. }
  1182. // =========================================
  1183. /**
  1184. * @ignore
  1185. */
  1186. protected function request_with_pager( $url , $page = false , $count = false )
  1187. {
  1188. $param = array();
  1189. if( $page ) $param['page'] = $page;
  1190. if( $count ) $param['count'] = $count;
  1191. return $this->oauth->get($url , $param );
  1192. }
  1193. /**
  1194. * @ignore
  1195. */
  1196. protected function request_with_uid( $url , $uid_or_name , $page = false , $count = false , $cursor = false , $post = false )
  1197. {
  1198. $param = array();
  1199. if( $page ) $param['page'] = $page;
  1200. if( $count ) $param['count'] = $count;
  1201. if( $cursor )$param['cursor'] = $cursor;
  1202. if( $post ) $method = 'post';
  1203. else $method = 'get';
  1204. if( is_numeric( $uid_or_name ) )
  1205. {
  1206. $param['user_id'] = $uid_or_name;
  1207. return $this->oauth->$method($url , $param );
  1208. }elseif( $uid_or_name !== null )
  1209. {
  1210. $param['screen_name'] = $uid_or_name;
  1211. return $this->oauth->$method($url , $param );
  1212. }
  1213. else
  1214. {
  1215. return $this->oauth->$method($url , $param );
  1216. }
  1217. }
  1218. }
  1219. /**
  1220. * qq OAuth 认证类
  1221. *
  1222. * @package sae
  1223. * @author Easy Chen
  1224. * @version 1.0
  1225. */
  1226. class WeiboOAuth {
  1227. /**
  1228. * Contains the last HTTP status code returned.
  1229. *
  1230. * @ignore
  1231. */
  1232. public $http_code;
  1233. /**
  1234. * Contains the last API call.
  1235. *
  1236. * @ignore
  1237. */
  1238. public $url;
  1239. /**
  1240. * Set up the API root URL.
  1241. *
  1242. * @ignore
  1243. */
  1244. public $host = "http://open.t.qq.com/api/";
  1245. /**
  1246. * Set timeout default.
  1247. *
  1248. * @ignore
  1249. */
  1250. public $timeout = 30;
  1251. /**
  1252. * Set connect timeout.
  1253. *
  1254. * @ignore
  1255. */
  1256. public $connecttimeout = 30;
  1257. /**
  1258. * Verify SSL Cert.
  1259. *
  1260. * @ignore
  1261. */
  1262. public $ssl_verifypeer = FALSE;
  1263. /**
  1264. * Respons format.
  1265. *
  1266. * @ignore
  1267. */
  1268. public $format = 'json';
  1269. /**
  1270. * Decode returned json data.
  1271. *
  1272. * @ignore
  1273. */
  1274. public $decode_json = TRUE;
  1275. /**
  1276. * Contains the last HTTP headers returned.
  1277. *
  1278. * @ignore
  1279. */
  1280. public $http_info;
  1281. /**
  1282. * Set the useragnet.
  1283. *
  1284. * @ignore
  1285. */
  1286. public $useragent = 'Sae T OAuth v0.2.0-beta2';
  1287. /* Immediately retry the API call if the response was not successful. */
  1288. //public $retry = TRUE;
  1289. /**
  1290. * Set API URLS
  1291. */
  1292. /**
  1293. * @ignore
  1294. */
  1295. function accessTokenURL() { return 'https://open.t.qq.com/cgi-bin/access_token'; }
  1296. /**
  1297. * @ignore
  1298. */
  1299. function authenticateURL() { return 'https://open.t.qq.com/cgi-bin/authenticate'; }
  1300. /**
  1301. * @ignore
  1302. */
  1303. function authorizeURL() { return 'https://open.t.qq.com/cgi-bin/authorize'; }
  1304. /**
  1305. * @ignore
  1306. */
  1307. function requestTokenURL() { return 'https://open.t.qq.com/cgi-bin/request_token'; }
  1308. /**
  1309. * Debug helpers
  1310. */
  1311. /**
  1312. * @ignore
  1313. */
  1314. function lastStatusCode() { return $this->http_status; }
  1315. /**
  1316. * @ignore
  1317. */
  1318. function lastAPICall() { return $this->last_api_call; }
  1319. /**
  1320. * construct WeiboOAuth object
  1321. */
  1322. function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) {
  1323. $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
  1324. $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);
  1325. if (!empty($oauth_token) && !empty($oauth_token_secret)) {
  1326. $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret);
  1327. } else {
  1328. $this->token = NULL;
  1329. }
  1330. }
  1331. /**
  1332. * Get a request_token from Weibo
  1333. *
  1334. * @return array a key/value array containing oauth_token and oauth_token_secret
  1335. */
  1336. function getRequestToken($oauth_callback = NULL) {
  1337. $parameters = array();
  1338. if (!empty($oauth_callback)) {
  1339. $parameters['oauth_callback'] = $oauth_callback;
  1340. }
  1341. $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters);
  1342. $token = OAuthUtil::parse_parameters($request);
  1343. $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
  1344. return $token;
  1345. }
  1346. /**
  1347. * Get the authorize URL
  1348. *
  1349. * @return string
  1350. */
  1351. function getAuthorizeURL($token, $sign_in_with_Weibo = TRUE , $url) {
  1352. if (is_array($token)) {
  1353. $token = $token['oauth_token'];
  1354. }
  1355. if (empty($sign_in_with_Weibo)) {
  1356. return $this->authorizeURL() . "?oauth_token={$token}&oauth_callback=" . urlencode($url);
  1357. } else {
  1358. return $this->authenticateURL() . "?oauth_token={$token}&oauth_callback=". urlencode($url);
  1359. }
  1360. }
  1361. /**
  1362. * Exchange the request token and secret for an access token and
  1363. * secret, to sign API calls.
  1364. *
  1365. * @return array array("oauth_token" => the access token,
  1366. * "oauth_token_secret" => the access secret)
  1367. */
  1368. function getAccessToken($oauth_verifier = FALSE, $oauth_token = false) {
  1369. $parameters = array();
  1370. if (!empty($oauth_verifier)) {
  1371. $parameters['oauth_verifier'] = $oauth_verifier;
  1372. }
  1373. $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters);
  1374. $token = OAuthUtil::parse_parameters($request);
  1375. $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
  1376. return $token;
  1377. }
  1378. /**
  1379. * GET wrappwer for oAuthRequest.
  1380. *
  1381. * @return mixed
  1382. */
  1383. function get($url, $parameters = array()) {
  1384. $response = $this->oAuthRequest($url, 'GET', $parameters);
  1385. if ($this->format === 'json' && $this->decode_json) {
  1386. return json_decode($response, true);
  1387. }
  1388. return $response;
  1389. }
  1390. /**
  1391. * POST wreapper for oAuthRequest.
  1392. *
  1393. * @return mixed
  1394. */
  1395. function post($url, $parameters = array() , $multi = false) {
  1396. $response = $this->oAuthRequest($url, 'POST', $parameters , $multi );
  1397. if ($this->format === 'json' && $this->decode_json) {
  1398. return json_decode($response, true);
  1399. }
  1400. return $response;
  1401. }
  1402. /**
  1403. * DELTE wrapper for oAuthReqeust.
  1404. *
  1405. * @return mixed
  1406. */
  1407. function delete($url, $parameters = array()) {
  1408. $response = $this->oAuthRequest($url, 'DELETE', $parameters);
  1409. if ($this->format === 'json' && $this->decode_json) {
  1410. return json_decode($response, true);
  1411. }
  1412. return $response;
  1413. }
  1414. /**
  1415. * Format and sign an OAuth / API request
  1416. *
  1417. * @return string
  1418. */
  1419. function oAuthRequest($url, $method, $parameters , $multi = false) {
  1420. if (strrpos($url, 'https://') !== 0) {
  1421. //$url = "{$this->host}{$url}format={$this->format}";
  1422. }
  1423. //echo $url ;
  1424. $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters);
  1425. $request->sign_request($this->sha1_method, $this->consumer, $this->token);
  1426. switch ($method) {
  1427. case 'GET':
  1428. // echo $request->to_url();
  1429. return $this->http($request->to_url(), 'GET');
  1430. default:
  1431. return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata($multi) , $multi );
  1432. }
  1433. }
  1434. /**
  1435. * Make an HTTP request
  1436. *
  1437. * @return string API results
  1438. */
  1439. function http($url, $method, $postfields = NULL , $multi = false) {
  1440. $this->http_info = array();
  1441. $ci = curl_init();
  1442. /* Curl settings */
  1443. curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
  1444. curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
  1445. curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
  1446. curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
  1447. curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
  1448. curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
  1449. curl_setopt($ci, CURLOPT_HEADER, FALSE);
  1450. switch ($method) {
  1451. case 'POST':
  1452. curl_setopt($ci, CURLOPT_POST, TRUE);
  1453. if (!empty($postfields)) {
  1454. curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
  1455. //echo "=====post data======\r\n";
  1456. //echo $postfields;
  1457. }
  1458. break;
  1459. case 'DELETE':
  1460. curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
  1461. if (!empty($postfields)) {
  1462. $url = "{$url}?{$postfields}";
  1463. }
  1464. }
  1465. $header_array = array();
  1466. /*
  1467. $header_array["FetchUrl"] = $url;
  1468. $header_array['TimeStamp'] = date('Y-m-d H:i:s');
  1469. $header_array['AccessKey'] = SAE_ACCESSKEY;
  1470. $content="FetchUrl";
  1471. $content.=$header_array["FetchUrl"];
  1472. $content.="TimeStamp";
  1473. $content.=$header_array['TimeStamp'];
  1474. $content.="AccessKey";
  1475. $content.=$header_array['AccessKey'];
  1476. $header_array['Signature'] = base64_encode(hash_hmac('sha256',$content, SAE_SECRETKEY ,true));
  1477. */
  1478. //curl_setopt($ci, CURLOPT_URL, SAE_FETCHURL_SERVICE_ADDRESS );
  1479. //print_r( $header_array );
  1480. $header_array2=array();
  1481. if( $multi )
  1482. $header_array2 = array("Content-Type: multipart/form-data; boundary=" . OAuthUtil::$boundary , "Expect: ");
  1483. foreach($header_array as $k => $v)
  1484. array_push($header_array2,$k.': '.$v);
  1485. curl_setopt($ci, CURLOPT_HTTPHEADER, $header_array2 );
  1486. curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE );
  1487. //echo $url."<hr/>";
  1488. curl_setopt($ci, CURLOPT_URL, $url);
  1489. $response = curl_exec($ci);
  1490. $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
  1491. $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
  1492. $this->url = $url;
  1493. //echo '=====info====='."\r\n";
  1494. //print_r( curl_getinfo($ci) );
  1495. //echo '=====$response====='."\r\n";
  1496. //print_r( $response );
  1497. curl_close ($ci);
  1498. return $response;
  1499. }
  1500. /**
  1501. * Get the header info to store.
  1502. *
  1503. * @return int
  1504. */
  1505. function getHeader($ch, $header) {
  1506. $i = strpos($header, ':');
  1507. if (!empty($i)) {
  1508. $key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
  1509. $value = trim(substr($header, $i + 2));
  1510. $this->http_header[$key] = $value;
  1511. }
  1512. return strlen($header);
  1513. }
  1514. }