Changeset 113146 in spip-zone


Ignore:
Timestamp:
Dec 29, 2018, 12:46:24 PM (3 months ago)
Author:
teddy.spip@…
Message:

PSR SPIP

Location:
_plugins_/twitter/trunk
Files:
22 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/twitter/trunk/action/ajouter_twitteraccount.php

    r77627 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315
     
    2022function action_ajouter_twitteraccount_dist($is_callback = false) {
    2123        include_spip("inc/autoriser");
    22         if(autoriser("ajouter","twitteraccount")){
    23                 if (!$is_callback){
     24        if (autoriser("ajouter", "twitteraccount")) {
     25                if (!$is_callback) {
    2426                        // au premier appel
    2527                        $securiser_action = charger_fonction('securiser_action', 'inc');
     
    2729
    2830                        include_spip("inc/autoriser");
    29                         if(autoriser("ajouter","twitteraccount")){
     31                        if (autoriser("ajouter", "twitteraccount")) {
    3032
    3133                                // lancer la demande d'autorisation en indiquant le nom de l'action qui sera rappelee au retour
    3234                                include_spip("action/twitter_oauth_authorize");
    33                                 twitter_oauth_authorize("ajouter_twitteraccount",_request('redirect'));
     35                                twitter_oauth_authorize("ajouter_twitteraccount", _request('redirect'));
    3436                        }
    35                 }
    36                 else {
     37                } else {
    3738                        // appel au retour de l'authorize
    3839                        // recuperer le screenname
     
    5455 *   twitter_token : token du compte a utiliser
    5556 *   twitter_token_secret : token secret du compte a utiliser
     57 *
    5658 * @return array
    5759 */
    58 function twitter_ajouter_twitteraccount($tokens){
     60function twitter_ajouter_twitteraccount($tokens) {
    5961        $cfg = @unserialize($GLOBALS['meta']['microblog']);
    6062
     
    6264        $options = $tokens;
    6365        $options['force'] = true;
    64         if ($res = twitter_api_call("account/verify_credentials","get",array(),$options)){
     66        if ($res = twitter_api_call("account/verify_credentials", "get", array(), $options)) {
    6567                $cfg['twitter_accounts'][$res['screen_name']] = array(
    6668                        'token' => $tokens['twitter_token'],
    6769                        'token_secret' => $tokens['twitter_token_secret'],
    6870                );
    69         }
    70         else {
     71        } else {
    7172                $cfg['twitter_accounts'][] = array(
    7273                        'token' => $tokens['twitter_token'],
    7374                        'token_secret' => $tokens['twitter_token_secret'],
    7475                );
    75                 spip_log("Echec account/verify_credentials lors de l'ajout d'un compte","twitter"._LOG_ERREUR);
     76                spip_log("Echec account/verify_credentials lors de l'ajout d'un compte", "twitter" . _LOG_ERREUR);
    7677        }
    7778        if (!isset($cfg['default_account'])
    78           OR !isset($cfg['twitter_accounts'][$cfg['default_account']])){
     79                OR !isset($cfg['twitter_accounts'][$cfg['default_account']])) {
    7980                $accounts = array_keys($cfg['twitter_accounts']);
    8081                $cfg['default_account'] = reset($accounts);
     
    8586        return $cfg;
    8687}
     88
    8789?>
  • _plugins_/twitter/trunk/action/preferer_twitteraccount.php

    r73558 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315
     
    1820 */
    1921function action_preferer_twitteraccount_dist($account = null) {
    20         if (is_null($account)){
     22        if (is_null($account)) {
    2123                $securiser_action = charger_fonction('securiser_action', 'inc');
    2224                $account = $securiser_action();
     
    2426
    2527        include_spip("inc/autoriser");
    26         if(autoriser("preferer","twitteraccount",$account)){
     28        if (autoriser("preferer", "twitteraccount", $account)) {
    2729
    2830                $cfg = @unserialize($GLOBALS['meta']['microblog']);
    29                 if (isset($cfg['twitter_accounts'][$account])){
     31                if (isset($cfg['twitter_accounts'][$account])) {
    3032                        $cfg['default_account'] = $account;
    3133
     
    3436        }
    3537}
     38
    3639?>
  • _plugins_/twitter/trunk/action/supprimer_twitteraccount.php

    r77627 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315
     
    1820 */
    1921function action_supprimer_twitteraccount_dist($account = null) {
    20         if (is_null($account)){
     22        if (is_null($account)) {
    2123                $securiser_action = charger_fonction('securiser_action', 'inc');
    2224                $account = $securiser_action();
     
    2426
    2527        include_spip("inc/autoriser");
    26         if(autoriser("supprimer","twitteraccount",$account)){
     28        if (autoriser("supprimer", "twitteraccount", $account)) {
    2729
    2830                $cfg = @unserialize($GLOBALS['meta']['microblog']);
    29                 if (isset($cfg['twitter_accounts'][$account])){
     31                if (isset($cfg['twitter_accounts'][$account])) {
    3032                        unset($cfg['twitter_accounts'][$account]);
    3133                        if (!isset($cfg['default_account'])
    32                           OR !isset($cfg['twitter_accounts'][$cfg['default_account']])){
     34                                OR !isset($cfg['twitter_accounts'][$cfg['default_account']])) {
    3335                                $accounts = array_keys($cfg['twitter_accounts']);
    3436                                $cfg['default_account'] = reset($accounts);
     
    3941        }
    4042}
     43
    4144?>
  • _plugins_/twitter/trunk/action/twidget.php

    r112849 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
    12 
    13 function action_twidget_dist(){
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
     14
     15function action_twidget_dist() {
    1416
    1517        $url = $_SERVER['QUERY_STRING'];
    16         $url = preg_replace(",^(.+&)?action=twidget&w=/?,","",$url);
    17 
    18         if (!_request('debug'))
     18        $url = preg_replace(",^(.+&)?action=twidget&w=/?,", "", $url);
     19
     20        if (!_request('debug')) {
    1921                header("Content-type: text/javascript; charset=utf-8");
     22        }
    2023
    2124        $res = twidget_get_cached_url($url);
    2225        // header Expires pour eviter overflow par le meme client
    2326        header("Pragma: public");
    24         header("Cache-Control: maxage="._EXPIRES);
    25         header('Expires: ' . gmdate('D, d M Y H:i:s', time()+_EXPIRES) . ' GMT');
     27        header("Cache-Control: maxage=" . _EXPIRES);
     28        header('Expires: ' . gmdate('D, d M Y H:i:s', time() + _EXPIRES) . ' GMT');
    2629
    2730        // toujours renvoyer un JSON acceptable, pour declencher la callback notamment :
    28         if (!strlen(trim($res))){
    29                 $res = twidget_return($res,_request('callback'));
     31        if (!strlen(trim($res))) {
     32                $res = twidget_return($res, _request('callback'));
    3033        }
    3134        echo $res;
     
    3437}
    3538
    36 function twidget_return($content,$callback=""){
    37         if (!strlen(trim($content)))
     39function twidget_return($content, $callback = "") {
     40        if (!strlen(trim($content))) {
    3841                $content = "[]";
    39         if ($callback)
    40                 $content = $callback."(".$content.");";
     42        }
     43        if ($callback) {
     44                $content = $callback . "(" . $content . ");";
     45        }
    4146
    4247        return $content;
     
    4449
    4550
    46 function twidget_get_cached_url($url,$force=false) {
     51function twidget_get_cached_url($url, $force = false) {
    4752        $callback = "";
    4853        // enlever le param anti cache
    49         $url = preg_replace(",&\d+=cachebust,","",$url);
     54        $url = preg_replace(",&\d+=cachebust,", "", $url);
    5055        // extraire la callback pour ne pas la cacher (mutualisation du cache)
    51         if (preg_match(",&callback=[^&]*,",$url,$m)){
    52                 $callback = substr($m[0],10);
    53                 $url = str_replace($m[0],"",$url);
    54         }
    55 
    56         @define('_TWIDGET_CACHE',180);
     56        if (preg_match(",&callback=[^&]*,", $url, $m)) {
     57                $callback = substr($m[0], 10);
     58                $url = str_replace($m[0], "", $url);
     59        }
     60
     61        @define('_TWIDGET_CACHE', 180);
    5762        $expires = _TWIDGET_CACHE;
    5863
    59         if (_request('debug')){
     64        if (_request('debug')) {
    6065                $force = true;
    61                 if (_request('debug')){
    62                         $d = "&debug="._request('debug');
    63                         $url = str_replace($d,"",$url);
     66                if (_request('debug')) {
     67                        $d = "&debug=" . _request('debug');
     68                        $url = str_replace($d, "", $url);
    6469                }
    6570        }
    6671
    6772        $hash = md5($url);
    68         $dir = sous_repertoire(_DIR_CACHE,"twidget");
    69 
    70         $f = "$dir"."p$hash.txt";
     73        $dir = sous_repertoire(_DIR_CACHE, "twidget");
     74
     75        $f = "$dir" . "p$hash.txt";
    7176
    7277
    7378        if (!$force
    74           AND lire_fichier($f, $c)
    75           AND $c = unserialize($c)
    76           AND isset($c['content'])
    77           // AND $contenu = trim($c['content'])
    78           AND time()-$c['time']<_TWIDGET_CACHE){
    79                 if (!defined('_EXPIRES')) define('_EXPIRES',$expires);
    80                 return twidget_return($c['content'],$callback);
    81         }
    82 
    83         spip_log("cache $f invalide (force $force)","twitget");
     79                AND lire_fichier($f, $c)
     80                AND $c = unserialize($c)
     81                AND isset($c['content'])
     82                // AND $contenu = trim($c['content'])
     83                AND time() - $c['time'] < _TWIDGET_CACHE) {
     84                if (!defined('_EXPIRES')) {
     85                        define('_EXPIRES', $expires);
     86                }
     87
     88                return twidget_return($c['content'], $callback);
     89        }
     90
     91        spip_log("cache $f invalide (force $force)", "twitget");
    8492        // si job_queue, programmer la maj et renvoyer le contenu existant
    8593        if (!$force
    86           // AND isset($c['content'])
    87           // AND $contenu = trim($c['content'])
    88           AND function_exists('job_queue_add')) {
    89                 job_queue_add ('twidget_get_cached_url', 'Twitter Widget proxy', array($url,true), 'action/twidget',true);
    90                 if (!defined('_EXPIRES')) define('_EXPIRES',$expires);
     94                // AND isset($c['content'])
     95                // AND $contenu = trim($c['content'])
     96                AND function_exists('job_queue_add')) {
     97                job_queue_add('twidget_get_cached_url', 'Twitter Widget proxy', array($url, true), 'action/twidget', true);
     98                if (!defined('_EXPIRES')) {
     99                        define('_EXPIRES', $expires);
     100                }
     101
    91102                return twidget_return(isset($c['content']) ? $c['content'] : '', $callback);
    92103        }
    93104
    94         spip_log("requete api twitter $url","twitget");
     105        spip_log("requete api twitter $url", "twitget");
    95106        // mettre a jour le cache
    96107
    97108
    98         $surl = explode("?",$url);
     109        $surl = explode("?", $url);
    99110        $command = array_shift($surl);
    100         $surl = implode("?",$surl);
    101         parse_str($surl,$query);
     111        $surl = implode("?", $surl);
     112        parse_str($surl, $query);
    102113
    103114        // reaffecter API v1 sur API v1.1
    104115        $command_v11 = $command;
    105         switch($command){
     116        switch ($command) {
    106117                case "search.json":
    107118                        $command_v11 = "search/tweets";
    108                         if (isset($query['rpp'])){
     119                        if (isset($query['rpp'])) {
    109120                                $query['count'] = $query['rpp'];
    110121                                unset($query['rpp']);
     
    112123                        break;
    113124                default:
    114                         $command_v11 = preg_replace(",^1/|\.json$,","",$command);
     125                        $command_v11 = preg_replace(",^1/|\.json$,", "", $command);
    115126                        break;
    116127        }
    117128        unset($query['clientsource']);
    118         if (isset($query['callback'])){
     129        if (isset($query['callback'])) {
    119130                $callback = $query['callback'];
    120131                unset($query['callback']);
     
    123134        include_spip("inc/twitter");
    124135
    125         $res = twitter_api_call($command_v11,"get",$query);
    126 
    127         if (_request('debug')){
     136        $res = twitter_api_call($command_v11, "get", $query);
     137
     138        if (_request('debug')) {
    128139                var_dump($url);
    129                 var_dump(array($command_v11,$query));
     140                var_dump(array($command_v11, $query));
    130141                var_dump($command);
    131142        }
    132143
    133144        // redresser la sortie API v1.1 => API v1
    134         switch($command){
     145        switch ($command) {
    135146                case "search.json":
    136147                        include_spip("inc/json");
    137                         foreach(array('completed_in','max_id','max_id_str','query') as $k)
    138                         $res[$k] = $res['search_metadata'][$k];
     148                        foreach (array('completed_in', 'max_id', 'max_id_str', 'query') as $k) {
     149                                $res[$k] = $res['search_metadata'][$k];
     150                        }
    139151                        $res['results'] = $res['statuses'];
    140                         foreach($res['results'] as $k=>$r){
     152                        foreach ($res['results'] as $k => $r) {
    141153                                $res['results'][$k]['from_user'] = $r['user']['screen_name'];
    142154                                $res['results'][$k]['profile_image_url'] = $r['user']['profile_image_url'];
     
    147159                        break;
    148160                case "1/statuses/user_timeline.json":
    149                         foreach($res as $k=>$r){
     161                        foreach ($res as $k => $r) {
    150162                                $res[$k]['profile_image_url'] = $r['user']['profile_image_url'];
    151163                        }
     
    157169        }
    158170
    159         if (_request('debug')){
     171        if (_request('debug')) {
    160172                var_dump($res);
    161173        }
     
    165177        // ne pas cacher une requete qui echoue (twitter fail)
    166178        if ($contenu
    167           OR !isset($c['content'])
    168           OR !strlen(trim($c['content']))){
     179                OR !isset($c['content'])
     180                OR !strlen(trim($c['content']))) {
    169181                include_spip("inc/filtres_mini");
    170                 $base = protocole_implicite(url_de_base(). (_DIR_RACINE ? _DIR_RESTREINT_ABS : ''));
     182                $base = protocole_implicite(url_de_base() . (_DIR_RACINE ? _DIR_RESTREINT_ABS : ''));
    171183
    172184                // intercepter, cacher et relocaliser les avatars
    173                 preg_match_all(',"profile_image_url(?:_https)?":"([^"]*)",Uims',$contenu,$regs,PREG_SET_ORDER);
    174                 foreach($regs as $reg){
    175                         if (_request('debug')){
     185                preg_match_all(',"profile_image_url(?:_https)?":"([^"]*)",Uims', $contenu, $regs, PREG_SET_ORDER);
     186                foreach ($regs as $reg) {
     187                        if (_request('debug')) {
    176188                                var_dump($reg);
    177189                        }
    178190                        $new = twidget_get_cached_avatar($reg[1]);
    179                         $new = url_absolue($new,$base);
    180                         if (_request('debug')){
     191                        $new = url_absolue($new, $base);
     192                        if (_request('debug')) {
    181193                                var_dump($new);
    182194                        }
    183                         $contenu = str_replace($reg[1],$new,$contenu);
    184                 }
    185 
    186                 ecrire_fichier($f, serialize(array('time'=>time(),'content'=>$contenu)));
     195                        $contenu = str_replace($reg[1], $new, $contenu);
     196                }
     197
     198                ecrire_fichier($f, serialize(array('time' => time(), 'content' => $contenu)));
    187199        }
    188200
     
    191203        // en limitation d'API
    192204        if (!$contenu) {
    193                 $expires = 15*60;
     205                $expires = 15 * 60;
    194206        }
    195207
    196208        // header Expires pour eviter overflow par le meme client
    197         if (!defined('_EXPIRES')) define('_EXPIRES',$expires);
    198         return twidget_return($contenu,$callback);
    199 
    200 }
    201 
    202 function twidget_get_cached_avatar($img_url){
    203 
    204         $img_url = str_replace('\/','/',$img_url);
    205 
    206         @define('_TWIDGET_CACHE_AVATAR',24*3600);
     209        if (!defined('_EXPIRES')) {
     210                define('_EXPIRES', $expires);
     211        }
     212
     213        return twidget_return($contenu, $callback);
     214
     215}
     216
     217function twidget_get_cached_avatar($img_url) {
     218
     219        $img_url = str_replace('\/', '/', $img_url);
     220
     221        @define('_TWIDGET_CACHE_AVATAR', 24 * 3600);
    207222        $parts = parse_url($img_url);
    208223
    209224        $hash = md5($parts['path']);
    210         $ext=".jpg";
    211         if ($p = strrpos($parts['path'], "."))
     225        $ext = ".jpg";
     226        if ($p = strrpos($parts['path'], ".")) {
    212227                $ext = substr($parts['path'], $p);
    213 
    214         $dir = sous_repertoire(_DIR_VAR,"twidget");
    215         $dir = sous_repertoire($dir,substr($hash,0,2));
    216         $f = $dir.$hash.$ext;
    217 
    218         if (file_exists($f) AND time()-filemtime($f)<_TWIDGET_CACHE_AVATAR)
     228        }
     229
     230        $dir = sous_repertoire(_DIR_VAR, "twidget");
     231        $dir = sous_repertoire($dir, substr($hash, 0, 2));
     232        $f = $dir . $hash . $ext;
     233
     234        if (file_exists($f) AND time() - filemtime($f) < _TWIDGET_CACHE_AVATAR) {
    219235                return $f;
    220 
    221         if (!function_exists("recuperer_page"))
     236        }
     237
     238        if (!function_exists("recuperer_page")) {
    222239                include_spip("inc/distant");
    223         recuperer_page($img_url,$f);
     240        }
     241        recuperer_page($img_url, $f);
     242
    224243        return $f;
    225244}
     245
    226246?>
  • _plugins_/twitter/trunk/action/twitter_oauth_authorize.php

    r91569 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315/**
    14  * Fonction vérifiant le retour de twitter 
    15  * Elle met dans la configuration du plugin les tokens 
     16 * Fonction vérifiant le retour de twitter
     17 * Elle met dans la configuration du plugin les tokens
    1618 * nécessaires pour de futures connexions
    1719 */
    18 function action_twitter_oauth_authorize_dist(){
     20function action_twitter_oauth_authorize_dist() {
    1921
    2022        include_spip('inc/twitteroauthspip');
     
    2325        $redirect = session_get('twitter_redirect') ? session_get('twitter_redirect') : $GLOBALS['meta']['url_site_spip'];
    2426        if (isset($GLOBALS['visiteur_session']['oauth_token'])
    25                 AND $GLOBALS['visiteur_session']['oauth_token']){
     27                AND $GLOBALS['visiteur_session']['oauth_token']) {
    2628
    27                 if(_request('denied')){
    28                         spip_log("action_twitter_oauth_authorize_dist : denied",'twitter'._LOG_ERREUR);
    29                         $redirect = parametre_url($redirect,'erreur','auth_denied','&');
    30                         session_set('oauth_status','denied');
     29                if (_request('denied')) {
     30                        spip_log("action_twitter_oauth_authorize_dist : denied", 'twitter' . _LOG_ERREUR);
     31                        $redirect = parametre_url($redirect, 'erreur', 'auth_denied', '&');
     32                        session_set('oauth_status', 'denied');
    3133                        $GLOBALS['redirect'] = $redirect;
    32                 }
    33                 elseif (_request('oauth_token') && ($GLOBALS['visiteur_session']['oauth_token'] !== _request('oauth_token'))) {
    34                         spip_log("action_twitter_oauth_authorize_dist : old_token",'twitter'._LOG_ERREUR);
    35                         $redirect = parametre_url($redirect,'erreur','old_token','&');
    36                         session_set('oauth_status','oldtoken');
     34                } elseif (_request('oauth_token') && ($GLOBALS['visiteur_session']['oauth_token'] !== _request('oauth_token'))) {
     35                        spip_log("action_twitter_oauth_authorize_dist : old_token", 'twitter' . _LOG_ERREUR);
     36                        $redirect = parametre_url($redirect, 'erreur', 'old_token', '&');
     37                        session_set('oauth_status', 'oldtoken');
    3738                        $GLOBALS['redirect'] = $redirect;
    38                 }
    39                 else {
     39                } else {
    4040                        $cfg = @unserialize($GLOBALS['meta']['microblog']);
    4141                        $consumer_key = $cfg['twitter_consumer_key'];
     
    4444                        $connection = new TwitterOAuthSPIP($consumer_key, $consumer_secret, $GLOBALS['visiteur_session']['oauth_token'], $GLOBALS['visiteur_session']['oauth_token_secret']);
    4545                        $access_token = $connection->getAccessToken(_request('oauth_verifier'));
    46                         session_set('access_token',$access_token);
     46                        session_set('access_token', $access_token);
    4747
    4848                        /**
     
    5555
    5656                                if ($callback = session_get('twitter_callback')
    57                                   AND $callback = charger_fonction($callback,"action",true)){
     57                                        AND $callback = charger_fonction($callback, "action", true)) {
    5858                                        // si la callback retourne quelque chose c'est une url de redirect
    59                                         if ($r = $callback(true, $redirect))
     59                                        if ($r = $callback(true, $redirect)) {
    6060                                                $redirect = $r;
     61                                        }
    6162                                }
    6263
    6364                                $GLOBALS['redirect'] = $redirect;
    64                         }
    65                         else {
    66                                 spip_log("Erreur '".$connection->http_code."' au retour pour recuperation des tokens dans action_twitter_oauth_callback_dist",'twitter'._LOG_ERREUR);
     65                        } else {
     66                                spip_log("Erreur '" . $connection->http_code . "' au retour pour recuperation des tokens dans action_twitter_oauth_callback_dist", 'twitter' . _LOG_ERREUR);
    6767                                // peut donner une info en plus, genre un message d'erreur a la place des tokens
    68                                 spip_log($access_token,'twitter'._LOG_ERREUR);
    69                                 $redirect = parametre_url($redirect,'erreur_code',$connection->http_code);
    70                                 if (count($access_token)==1
    71                                   AND $e = trim(implode(" ",array_keys($access_token))." ".implode(" ",array_values($access_token)))){
    72                                         session_set("oauth_erreur_message","Erreur : $e");
    73                                         $redirect = parametre_url($redirect,'erreur','erreur_oauth','&');
    74                                 }
    75                                 else {
    76                                         $redirect = parametre_url($redirect,'erreur','auth_denied','&');
     68                                spip_log($access_token, 'twitter' . _LOG_ERREUR);
     69                                $redirect = parametre_url($redirect, 'erreur_code', $connection->http_code);
     70                                if (count($access_token) == 1
     71                                        AND $e = trim(implode(" ", array_keys($access_token)) . " " . implode(" ", array_values($access_token)))) {
     72                                        session_set("oauth_erreur_message", "Erreur : $e");
     73                                        $redirect = parametre_url($redirect, 'erreur', 'erreur_oauth', '&');
     74                                } else {
     75                                        $redirect = parametre_url($redirect, 'erreur', 'auth_denied', '&');
    7776                                }
    7877                                $GLOBALS['redirect'] = $redirect;
    7978                        }
    8079                }
    81         }
    82         else {
     80        } else {
    8381                // rien a faire ici !
    8482                $GLOBALS['redirect'] = $redirect;
     
    8684
    8785        // vider la session
    88         foreach(array('access_token','oauth_token','oauth_token_secret','twitter_redirect','twitter_callback') as $k)
    89                 if (isset($GLOBALS['visiteur_session'][$k]))
     86        foreach (array('access_token', 'oauth_token', 'oauth_token_secret', 'twitter_redirect', 'twitter_callback') as $k) {
     87                if (isset($GLOBALS['visiteur_session'][$k])) {
    9088                        session_set($k);
     89                }
     90        }
    9191}
    9292
    93 function twitter_oauth_authorize($callback, $redirect, $sign_in=true){
     93function twitter_oauth_authorize($callback, $redirect, $sign_in = true) {
    9494        $cfg = @unserialize($GLOBALS['meta']['microblog']);
    9595
    96         $redirect = parametre_url(parametre_url($redirect,'erreur_code',''),'erreur','','&');
     96        $redirect = parametre_url(parametre_url($redirect, 'erreur_code', ''), 'erreur', '', '&');
    9797
    9898        include_spip('inc/filtres');
     
    104104         * Elle vérifiera le retour et finira la configuration
    105105         */
    106         $oauth_callback = url_absolue(generer_url_action('twitter_oauth_authorize','',true));
     106        $oauth_callback = url_absolue(generer_url_action('twitter_oauth_authorize', '', true));
    107107
    108108        /**
     
    115115                $request_token = $connection->getRequestToken($oauth_callback);
    116116                $token = $request_token['oauth_token'];
    117                 session_set('oauth_token',$token);
    118                 session_set('oauth_token_secret',$request_token['oauth_token_secret']);
    119                 session_set('twitter_redirect',str_replace('&amp;','&',$redirect));
    120                 session_set('twitter_callback',$callback);
     117                session_set('oauth_token', $token);
     118                session_set('oauth_token_secret', $request_token['oauth_token_secret']);
     119                session_set('twitter_redirect', str_replace('&amp;', '&', $redirect));
     120                session_set('twitter_callback', $callback);
    121121
    122122                /**
     
    138138                         */
    139139                        default:
    140                                 spip_log('Erreur connexion twitter','twitter'._LOG_ERREUR);
    141                                 spip_log($connection, 'twitter'._LOG_ERREUR);
    142                                 $redirect = parametre_url($redirect,'erreur_code',$code);
    143                                 $redirect = parametre_url($redirect,'erreur','erreur_conf_app','&');
     140                                spip_log('Erreur connexion twitter', 'twitter' . _LOG_ERREUR);
     141                                spip_log($connection, 'twitter' . _LOG_ERREUR);
     142                                $redirect = parametre_url($redirect, 'erreur_code', $code);
     143                                $redirect = parametre_url($redirect, 'erreur', 'erreur_conf_app', '&');
    144144                                $GLOBALS['redirect'] = $redirect;
    145145                                break;
    146146                }
    147         }
    148         catch(Exception $e){
    149                 session_set('oauth_erreur_message',$e->getMessage());
    150                 $redirect = parametre_url($redirect,'erreur',"erreur_oauth",'&');
     147        } catch (Exception $e) {
     148                session_set('oauth_erreur_message', $e->getMessage());
     149                $redirect = parametre_url($redirect, 'erreur', "erreur_oauth", '&');
    151150                $GLOBALS['redirect'] = $redirect;
    152151        }
    153152}
     153
    154154?>
  • _plugins_/twitter/trunk/formulaires/configurer_microblog.php

    r73676 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315
    14 function formulaires_configurer_microblog_verifier_dist(){
     16function formulaires_configurer_microblog_verifier_dist() {
    1517
    1618        $erreurs = array();
    1719
    1820        // si secret vide, reprendre celui de la config actuelle
    19         if (!trim(_request('twitter_consumer_secret')) AND _request('twitter_consumer_key')){
     21        if (!trim(_request('twitter_consumer_secret')) AND _request('twitter_consumer_key')) {
    2022                include_spip("inc/config");
    21                 set_request('twitter_consumer_secret',lire_config("microblog/twitter_consumer_secret"));
     23                set_request('twitter_consumer_secret', lire_config("microblog/twitter_consumer_secret"));
    2224        }
    2325
     
    2931
    3032
     33function twitter_masquer_secret($secret) {
     34        $affiche = "";
     35        if (strlen($secret)) {
     36                $affiche = substr($secret, 0, 4) . str_pad("*", strlen($secret) - 8, "*") . substr($secret, -4);
     37        }
    3138
    32 function twitter_masquer_secret($secret){
    33         $affiche = "";
    34         if (strlen($secret))
    35                 $affiche = substr($secret,0,4).str_pad("*",strlen($secret)-8,"*").substr($secret,-4);
    3639        return $affiche;
    3740}
    3841
    39 function twitter_affiche_erreur_config($erreur, $erreur_code){
     42function twitter_affiche_erreur_config($erreur, $erreur_code) {
    4043        static $message_erreur = array();
    41         if (!$erreur)
     44        if (!$erreur) {
    4245                return "";
     46        }
    4347
    4448        $key = "$erreur-$erreur_code";
    45         if (isset($message_erreur[$key]))
     49        if (isset($message_erreur[$key])) {
    4650                return $message_erreur[$key];
     51        }
    4752
    4853        static $status_string = array(
     
    5560                403 => '403 Forbidden',
    5661                404 => '404 Not Found',
    57                 503 => '503 Service Unavailable'
     62                503 => '503 Service Unavailable',
    5863        );
    5964
    60         switch($erreur){
     65        switch ($erreur) {
    6166                case "auth_denied":
    6267                        $err = "Ajout du compte refusé.";
     
    6873                        $err = session_get("oauth_erreur_message");
    6974                        session_set("oauth_erreur_message");
    70                         if (!$err)
     75                        if (!$err) {
    7176                                $err = "???";
     77                        }
    7278                        break;
    7379                case "erreur_conf_app":
     
    7783        }
    7884
    79         if ($erreur_code)
    80                 $err .= "<br />Le serveur a repondu <b>".(isset($status_string[$erreur_code])?$status_string[$erreur_code]:$erreur_code)."</b>";
    81         if ($erreur_code==401)
     85        if ($erreur_code) {
     86                $err .= "<br />Le serveur a repondu <b>" . (isset($status_string[$erreur_code]) ? $status_string[$erreur_code] : $erreur_code) . "</b>";
     87        }
     88        if ($erreur_code == 401) {
    8289                $err .= "<br />Avez-vous bien rempli le champ \"Callback URL\" de votre application Twitter ?";
     90        }
    8391
    8492        return $message_erreur[$key] = "<p>$err</p>";
  • _plugins_/twitter/trunk/formulaires/editer_microblog.php

    r107411 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315
     
    1517 * Fonction de chargement des valeurs par defaut des champs du formulaire
    1618 */
    17 function formulaires_editer_microblog_charger_dist($objet,$id_objet,$hide_form=false){
     19function formulaires_editer_microblog_charger_dist($objet, $id_objet, $hide_form = false) {
    1820        $primary = id_table_objet($objet);
    1921
    2022        $valeurs = array();
    21         $valeurs['_hide'] = (($hide_form AND is_null(_request('microblog')))?' ':'');
    22         $valeurs['objet']=$objet;
    23         $valeurs['id_objet']=$id_objet;
    24         $valeurs['microblog'] = recuperer_fond("modeles/microblog_instituer".$objet,array($primary=>$id_objet));
     23        $valeurs['_hide'] = (($hide_form AND is_null(_request('microblog'))) ? ' ' : '');
     24        $valeurs['objet'] = $objet;
     25        $valeurs['id_objet'] = $id_objet;
     26        $valeurs['microblog'] = recuperer_fond("modeles/microblog_instituer" . $objet, array($primary => $id_objet));
    2527        $valeurs['_status'] = trim($valeurs['microblog']);
    2628
    2729        include_spip("inc/twitter");
    28         if (!twitter_verifier_config()){
     30        if (!twitter_verifier_config()) {
    2931                $valeurs['editable'] = false;
    3032                $valeurs['message_erreur'] = _T('twitter:erreur_config_pour_tweeter');
     
    3638/**
    3739 * Fonction de vérification du formulaire avant traitement
    38  * 
     40 *
    3941 * Vérifie la présence d'un statut depuis le champs adéquat
    4042 * Vérifie que la longueur du statut n'excède pas la longueur maximale
    4143 */
    42 function formulaires_editer_microblog_verifier_dist($objet,$id_objet){
     44function formulaires_editer_microblog_verifier_dist($objet, $id_objet) {
    4345        include_spip('inc/charsets');
    4446        $erreurs = array();
    4547        $microblog = _request('microblog');
    46         if (spip_strlen($microblog)>280){
     48        if (spip_strlen($microblog) > 280) {
    4749                $erreurs['microblog'] = _T('twitter:longueur_maxi_status');
    4850        }
     
    5557 * Fonction de traitement du formulaire
    5658 * Envoie la contribution au service configuré
    57  * 
    58  * S'il y a une erreur en retour (false), 
     59 *
     60 * S'il y a une erreur en retour (false),
    5961 * on affiche un message explicitant qu'il y a une erreur dans la configuration
    6062 */
    61 function formulaires_editer_microblog_traiter_dist($objet,$id_objet){
    62         $res = array('editable'=>true);
     63function formulaires_editer_microblog_traiter_dist($objet, $id_objet) {
     64        $res = array('editable' => true);
    6365        $microblog = _request('microblog');
    64         if (_request('annuler_microblog'))
    65                 $microblog = " ";// ruse pour ne rien envoyer
    66         if (!is_null($microblog)){
    67                 $set = array('microblog'=>$microblog);
     66        if (_request('annuler_microblog')) {
     67                $microblog = " ";
     68        }// ruse pour ne rien envoyer
     69        if (!is_null($microblog)) {
     70                $set = array('microblog' => $microblog);
    6871                if (include_spip('action/editer_objet')
    69                   AND function_exists('objet_modifier'))
     72                        AND function_exists('objet_modifier')) {
    7073                        objet_modifier($objet, $id_objet, $set);
    71                 elseif(include_spip('inc/modifier')
    72                   AND function_exists($f="revision_$objet"))
     74                } elseif (include_spip('inc/modifier')
     75                        AND function_exists($f = "revision_$objet")) {
    7376                        $f($id_objet, $set);
     77                }
    7478        }
    75         if (!strlen(trim($microblog)))
     79        if (!strlen(trim($microblog))) {
    7680                set_request('microblog');
     81        }
    7782
    78         if (_request('envoyer')){
     83        if (_request('envoyer')) {
    7984                include_spip('inc/microblog');
    8085                $primary = id_table_objet($objet);
    81                 $status = recuperer_fond("modeles/microblog_instituer".$objet,array($primary=>$id_objet));
     86                $status = recuperer_fond("modeles/microblog_instituer" . $objet, array($primary => $id_objet));
    8287                $retour = microblog($status);
    83                 if($retour){
    84                         $res['message_ok']=_T('twitter:message_envoye')." ".$status;
    85                 }
    86                 else{
    87                         $res['message_erreur']=_T('twitter:erreur_verifier_configuration');
     88                if ($retour) {
     89                        $res['message_ok'] = _T('twitter:message_envoye') . " " . $status;
     90                } else {
     91                        $res['message_erreur'] = _T('twitter:erreur_verifier_configuration');
    8892                }
    8993        }
  • _plugins_/twitter/trunk/formulaires/microbloguer.php

    r107411 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315/**
    1416 * Fonction de chargement des valeurs par defaut des champs du formulaire
    1517 */
    16 function formulaires_microbloguer_charger_dist(){
     18function formulaires_microbloguer_charger_dist() {
    1719        $valeurs =
    1820                array(
     
    2022                );
    2123        include_spip("inc/twitter");
    22         if (!twitter_verifier_config()){
     24        if (!twitter_verifier_config()) {
    2325                $valeurs['editable'] = false;
    2426                $valeurs['message_erreur'] = _T('twitter:erreur_config_pour_tweeter');
    2527        }
     28
    2629        return $valeurs;
    2730}
     
    2932/**
    3033 * Fonction de vérification du formulaire avant traitement
    31  * 
     34 *
    3235 * Vérifie la présence d'un statut depuis le champs adéquat
    3336 * Vérifie que la longueur du statut n'excède pas la longueur maximale
    3437 */
    35 function formulaires_microbloguer_verifier_dist(){
     38function formulaires_microbloguer_verifier_dist() {
    3639        include_spip('inc/charsets');
    3740        $erreurs = array();
    38         if (!$status = _request('status')){
     41        if (!$status = _request('status')) {
    3942                $erreurs['status'] = _T('info_obligatoire');
    40         }
    41         elseif (spip_strlen($status)>280){
     43        } elseif (spip_strlen($status) > 280) {
    4244                $erreurs['status'] = _T('twitter:longueur_maxi_status');
    4345        }
     
    5052 * Fonction de traitement du formulaire
    5153 * Envoie la contribution au service configuré
    52  * 
    53  * S'il y a une erreur en retour (false), 
     54 *
     55 * S'il y a une erreur en retour (false),
    5456 * on affiche un message explicitant qu'il y a une erreur dans la configuration
    5557 */
    56 function formulaires_microbloguer_traiter_dist(){
     58function formulaires_microbloguer_traiter_dist() {
    5759        $res = array();
    58         if ($status = _request('status')){
     60        if ($status = _request('status')) {
    5961                include_spip('inc/microblog');
    6062                $retour = microblog($status);
    61                 spip_log($retour,'twitter');
    62                
    63                 if($retour){
    64                         set_request('status','');
    65                         $res = array('message_ok'=>_T('twitter:message_envoye')." ".$status,'editable'=>true);
    66                 }else{
     63                spip_log($retour, 'twitter');
     64
     65                if ($retour) {
     66                        set_request('status', '');
     67                        $res = array('message_ok' => _T('twitter:message_envoye') . " " . $status, 'editable' => true);
     68                } else {
    6769                        $erreur = _T('twitter:erreur_verifier_configuration');
    68                         if (defined('_TEST_MICROBLOG_SERVICE') AND !_TEST_MICROBLOG_SERVICE)
     70                        if (defined('_TEST_MICROBLOG_SERVICE') AND !_TEST_MICROBLOG_SERVICE) {
    6971                                $erreur = _T('twitter:erreur_envoi_desactive');
    70                         $res = array('message_erreur'=>$erreur,'editable'=>true);
     72                        }
     73                        $res = array('message_erreur' => $erreur, 'editable' => true);
    7174                }
     75        } else {
     76                $res = array('message_erreur' => '???', 'editable' => true);
    7277        }
    73         else
    74                 $res = array('message_erreur'=>'???','editable'=>true);
    7578
    7679        return
  • _plugins_/twitter/trunk/genie/twitter.php

    r89064 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315/**
     
    1517 *
    1618 * @param int $last
     19 *
    1720 * @return int
    1821 */
     
    2326        // il faut surveiller les articles publies
    2427        // $last est la date de la dernier occurence du cron, si vaut zero on ne fait rien
    25         if ($GLOBALS['meta']["post_dates"]=='non'
    26         and $cfg['evt_publierarticles']
    27         AND $cfg['evt_publierarticlesfutur']=='publication'
    28         AND $last){
     28        if ($GLOBALS['meta']["post_dates"] == 'non'
     29                and $cfg['evt_publierarticles']
     30                AND $cfg['evt_publierarticlesfutur'] == 'publication'
     31                AND $last) {
    2932                include_spip('inc/abstract_sql');
    30                 $deja_annonces = explode(',',$GLOBALS['meta']['twitter_annonces']);
    31                 $deja_annonces = array_map('intval',$deja_annonces);
     33                $deja_annonces = explode(',', $GLOBALS['meta']['twitter_annonces']);
     34                $deja_annonces = array_map('intval', $deja_annonces);
    3235
    33                 $res = sql_select("id_article,statut","spip_articles",
     36                $res = sql_select("id_article,statut", "spip_articles",
    3437                        array(
    3538                                "statut='publie'",
    36                                 "date>".sql_quote(date("Y-m-d H:i:s",$last)),
    37                                 "date<=".sql_quote(date("Y-m-d H:i:s")),
    38                                 sql_in('id_article',$deja_annonces,"NOT")
     39                                "date>" . sql_quote(date("Y-m-d H:i:s", $last)),
     40                                "date<=" . sql_quote(date("Y-m-d H:i:s")),
     41                                sql_in('id_article', $deja_annonces, "NOT"),
    3942                        ));
    4043                include_spip('inc/twitter_notifications');
    4144                include_spip('inc/twitter');
    42                 while($row = sql_fetch($res)){
    43                         $status = twitter_annonce('instituerarticle',array('id_article'=>$row['id_article']));
    44                         twitter_envoyer_tweet($status,array('objet'=>'article','id_objet'=>$row['id_article']));
     45                while ($row = sql_fetch($res)) {
     46                        $status = twitter_annonce('instituerarticle', array('id_article' => $row['id_article']));
     47                        twitter_envoyer_tweet($status, array('objet' => 'article', 'id_objet' => $row['id_article']));
    4548                }
    4649                // raz des annonces deja faites
    4750                include_spip('inc/meta');
    48                 ecrire_meta('twitter_annonces','0');
     51                ecrire_meta('twitter_annonces', '0');
    4952        }
    5053
     
    5457/**
    5558 * Ajouter la tache cron pour tweeter les articles post-dates, chaque heure
     59 *
    5660 * @param $taches_generales
     61 *
    5762 * @return mixed
    5863 */
    59 function twitter_taches_generales_cron($taches_generales){
    60         if ($GLOBALS['meta']["post_dates"]=='non'
    61                 AND     $cfg = @unserialize($GLOBALS['meta']['microblog'])
     64function twitter_taches_generales_cron($taches_generales) {
     65        if ($GLOBALS['meta']["post_dates"] == 'non'
     66                AND $cfg = @unserialize($GLOBALS['meta']['microblog'])
    6267                and $cfg['evt_publierarticles']
    63                 AND $cfg['evt_publierarticlesfutur']=='publication'){
     68                AND $cfg['evt_publierarticlesfutur'] == 'publication') {
    6469                // surveiller toutes les heures les publications post-dates
    6570                $taches_generales['twitter'] = 3600;
    6671        }
     72
    6773        return $taches_generales;
    6874}
  • _plugins_/twitter/trunk/inc/OAuth.php

    r106454 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315// vim: foldmethod=marker
     
    1517
    1618if (!function_exists('hash_hmac')) {
    17 function hash_hmac($algo, $data, $key, $raw_output = false) {
    18         $blocksize = 64;
    19         if (strlen($key)>$blocksize) {
    20                 $key = pack('H*', $algo($key));
    21         }
    22         $key  = str_pad($key, $blocksize, chr(0));
    23         $ipad = str_repeat(chr(0x36), $blocksize);
    24         $opad = str_repeat(chr(0x5c), $blocksize);
    25         $res = $algo(($key^$opad) . pack('H*', $algo(($key^$ipad) . $data)));
    26         if ($raw_output)
    27                 $res = pack('H*', $res);
    28         return $res;
    29 }
     19        function hash_hmac($algo, $data, $key, $raw_output = false) {
     20                $blocksize = 64;
     21                if (strlen($key) > $blocksize) {
     22                        $key = pack('H*', $algo($key));
     23                }
     24                $key = str_pad($key, $blocksize, chr(0));
     25                $ipad = str_repeat(chr(0x36), $blocksize);
     26                $opad = str_repeat(chr(0x5c), $blocksize);
     27                $res = $algo(($key ^ $opad) . pack('H*', $algo(($key ^ $ipad) . $data)));
     28                if ($raw_output) {
     29                        $res = pack('H*', $res);
     30                }
     31
     32                return $res;
     33        }
    3034}
    3135
    3236/* Generic exception class
    3337 */
     38
    3439class OAuthException extends Exception {
    35   // pass
     40        // pass
    3641}
    3742
    3843class OAuthConsumer {
    39   public $key;
    40   public $secret;
    41 
    42   function __construct($key, $secret, $callback_url=NULL) {
    43     $this->key = $key;
    44     $this->secret = $secret;
    45     $this->callback_url = $callback_url;
    46   }
    47 
    48   function __toString() {
    49     return "OAuthConsumer[key=$this->key,secret=$this->secret]";
    50   }
     44        public $key;
     45        public $secret;
     46
     47        function __construct($key, $secret, $callback_url = null) {
     48                $this->key = $key;
     49                $this->secret = $secret;
     50                $this->callback_url = $callback_url;
     51        }
     52
     53        function __toString() {
     54                return "OAuthConsumer[key=$this->key,secret=$this->secret]";
     55        }
    5156}
    5257
    5358class OAuthToken {
    54   // access tokens and request tokens
    55   public $key;
    56   public $secret;
    57 
    58   /**
    59   * key = the token
    60   * secret = the token secret
    61   */
    62   function __construct($key, $secret) {
    63     $this->key = $key;
    64     $this->secret = $secret;
    65   }
    66 
    67   /**
    68   * generates the basic string serialization of a token that a server
    69   * would respond to request_token and access_token calls with
    70   */
    71   function to_string() {
    72     return "oauth_token=" .
    73            OAuthUtil::urlencode_rfc3986($this->key) .
    74            "&oauth_token_secret=" .
    75            OAuthUtil::urlencode_rfc3986($this->secret);
    76   }
    77 
    78   function __toString() {
    79     return $this->to_string();
    80   }
     59        // access tokens and request tokens
     60        public $key;
     61        public $secret;
     62
     63        /**
     64        * key = the token
     65        * secret = the token secret
     66        */
     67        function __construct($key, $secret) {
     68                $this->key = $key;
     69                $this->secret = $secret;
     70        }
     71
     72        /**
     73        * generates the basic string serialization of a token that a server
     74        * would respond to request_token and access_token calls with
     75        */
     76        function to_string() {
     77                return "oauth_token=" .
     78                        OAuthUtil::urlencode_rfc3986($this->key) .
     79                        "&oauth_token_secret=" .
     80                        OAuthUtil::urlencode_rfc3986($this->secret);
     81        }
     82
     83        function __toString() {
     84                return $this->to_string();
     85        }
    8186}
    8287
     
    8691 */
    8792abstract class OAuthSignatureMethod {
    88   /**
    89    * Needs to return the name of the Signature Method (ie HMAC-SHA1)
    90    * @return string
    91    */
    92   abstract public function get_name();
    93 
    94   /**
    95    * Build up the signature
    96    * NOTE: The output of this function MUST NOT be urlencoded.
    97    * the encoding is handled in OAuthRequest when the final
    98    * request is serialized
    99    * @param OAuthRequest $request
    100    * @param OAuthConsumer $consumer
    101    * @param OAuthToken $token
    102    * @return string
    103    */
    104   abstract public function build_signature($request, $consumer, $token);
    105 
    106   /**
    107    * Verifies that a given signature is correct
    108    * @param OAuthRequest $request
    109    * @param OAuthConsumer $consumer
    110    * @param OAuthToken $token
    111    * @param string $signature
    112    * @return bool
    113    */
    114   public function check_signature($request, $consumer, $token, $signature) {
    115     $built = $this->build_signature($request, $consumer, $token);
    116     return $built == $signature;
    117   }
     93        /**
     94         * Needs to return the name of the Signature Method (ie HMAC-SHA1)
     95         *
     96         * @return string
     97         */
     98        abstract public function get_name();
     99
     100        /**
     101         * Build up the signature
     102         * NOTE: The output of this function MUST NOT be urlencoded.
     103         * the encoding is handled in OAuthRequest when the final
     104         * request is serialized
     105         *
     106         * @param OAuthRequest $request
     107         * @param OAuthConsumer $consumer
     108         * @param OAuthToken $token
     109         *
     110         * @return string
     111         */
     112        abstract public function build_signature($request, $consumer, $token);
     113
     114        /**
     115         * Verifies that a given signature is correct
     116         *
     117         * @param OAuthRequest $request
     118         * @param OAuthConsumer $consumer
     119         * @param OAuthToken $token
     120         * @param string $signature
     121         *
     122         * @return bool
     123         */
     124        public function check_signature($request, $consumer, $token, $signature) {
     125                $built = $this->build_signature($request, $consumer, $token);
     126
     127                return $built == $signature;
     128        }
    118129}
    119130
    120131/**
    121  * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] 
    122  * where the Signature Base String is the text and the key is the concatenated values (each first 
    123  * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&' 
     132 * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
     133 * where the Signature Base String is the text and the key is the concatenated values (each first
     134 * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
    124135 * character (ASCII code 38) even if empty.
    125136 *   - Chapter 9.2 ("HMAC-SHA1")
    126137 */
    127138class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
    128   function get_name() {
    129     return "HMAC-SHA1";
    130   }
    131 
    132   public function build_signature($request, $consumer, $token) {
    133     $base_string = $request->get_signature_base_string();
    134     $request->base_string = $base_string;
    135 
    136     $key_parts = array(
    137       $consumer->secret,
    138       ($token) ? $token->secret : ""
    139     );
    140 
    141     $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
    142     $key = implode('&', $key_parts);
    143 
    144     return base64_encode(hash_hmac('sha1', $base_string, $key, true));
    145   }
     139        function get_name() {
     140                return "HMAC-SHA1";
     141        }
     142
     143        public function build_signature($request, $consumer, $token) {
     144                $base_string = $request->get_signature_base_string();
     145                $request->base_string = $base_string;
     146
     147                $key_parts = array(
     148                        $consumer->secret,
     149                        ($token) ? $token->secret : "",
     150                );
     151
     152                $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
     153                $key = implode('&', $key_parts);
     154
     155                return base64_encode(hash_hmac('sha1', $base_string, $key, true));
     156        }
    146157}
    147158
    148159/**
    149  * The PLAINTEXT method does not provide any security protection and SHOULD only be used 
     160 * The PLAINTEXT method does not provide any security protection and SHOULD only be used
    150161 * over a secure channel such as HTTPS. It does not use the Signature Base String.
    151162 *   - Chapter 9.4 ("PLAINTEXT")
    152163 */
    153164class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
    154   public function get_name() {
    155     return "PLAINTEXT";
    156   }
    157 
    158   /**
    159    * oauth_signature is set to the concatenated encoded values of the Consumer Secret and
    160    * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
    161   * empty. The result MUST be encoded again.
    162   *   - Chapter 9.4.1 ("Generating Signatures")
    163   *
    164   * Please note that the second encoding MUST NOT happen in the SignatureMethod, as
    165   * OAuthRequest handles this!
    166   */
    167   public function build_signature($request, $consumer, $token) {
    168     $key_parts = array(
    169       $consumer->secret,
    170       ($token) ? $token->secret : ""
    171     );
    172 
    173     $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
    174     $key = implode('&', $key_parts);
    175     $request->base_string = $key;
    176 
    177     return $key;
    178   }
     165        public function get_name() {
     166                return "PLAINTEXT";
     167        }
     168
     169        /**
     170         * oauth_signature is set to the concatenated encoded values of the Consumer Secret and
     171         * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
     172        * empty. The result MUST be encoded again.
     173        *   - Chapter 9.4.1 ("Generating Signatures")
     174        *
     175        * Please note that the second encoding MUST NOT happen in the SignatureMethod, as
     176        * OAuthRequest handles this!
     177        */
     178        public function build_signature($request, $consumer, $token) {
     179                $key_parts = array(
     180                        $consumer->secret,
     181                        ($token) ? $token->secret : "",
     182                );
     183
     184                $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
     185                $key = implode('&', $key_parts);
     186                $request->base_string = $key;
     187
     188                return $key;
     189        }
    179190}
    180191
    181192/**
    182  * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in 
    183  * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for 
    184  * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a 
    185  * verified way to the Service Provider, in a manner which is beyond the scope of this 
     193 * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
     194 * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
     195 * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
     196 * verified way to the Service Provider, in a manner which is beyond the scope of this
    186197 * specification.
    187198 *   - Chapter 9.3 ("RSA-SHA1")
    188199 */
    189200abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
    190   public function get_name() {
    191     return "RSA-SHA1";
    192   }
    193 
    194   // Up to the SP to implement this lookup of keys. Possible ideas are:
    195   // (1) do a lookup in a table of trusted certs keyed off of consumer
    196   // (2) fetch via http using a url provided by the requester
    197   // (3) some sort of specific discovery code based on request
    198   //
    199   // Either way should return a string representation of the certificate
    200   protected abstract function fetch_public_cert(&$request);
    201 
    202   // Up to the SP to implement this lookup of keys. Possible ideas are:
    203   // (1) do a lookup in a table of trusted certs keyed off of consumer
    204   //
    205   // Either way should return a string representation of the certificate
    206   protected abstract function fetch_private_cert(&$request);
    207 
    208   public function build_signature($request, $consumer, $token) {
    209     $base_string = $request->get_signature_base_string();
    210     $request->base_string = $base_string;
    211 
    212     // Fetch the private key cert based on the request
    213     $cert = $this->fetch_private_cert($request);
    214 
    215     // Pull the private key ID from the certificate
    216     $privatekeyid = openssl_get_privatekey($cert);
    217 
    218     // Sign using the key
    219     $ok = openssl_sign($base_string, $signature, $privatekeyid);
    220 
    221     // Release the key resource
    222     openssl_free_key($privatekeyid);
    223 
    224     return base64_encode($signature);
    225   }
    226 
    227   public function check_signature($request, $consumer, $token, $signature) {
    228     $decoded_sig = base64_decode($signature);
    229 
    230     $base_string = $request->get_signature_base_string();
    231 
    232     // Fetch the public key cert based on the request
    233     $cert = $this->fetch_public_cert($request);
    234 
    235     // Pull the public key ID from the certificate
    236     $publickeyid = openssl_get_publickey($cert);
    237 
    238     // Check the computed signature against the one passed in the query
    239     $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
    240 
    241     // Release the key resource
    242     openssl_free_key($publickeyid);
    243 
    244     return $ok == 1;
    245   }
     201        public function get_name() {
     202                return "RSA-SHA1";
     203        }
     204
     205        // Up to the SP to implement this lookup of keys. Possible ideas are:
     206        // (1) do a lookup in a table of trusted certs keyed off of consumer
     207        // (2) fetch via http using a url provided by the requester
     208        // (3) some sort of specific discovery code based on request
     209        //
     210        // Either way should return a string representation of the certificate
     211        protected abstract function fetch_public_cert(&$request);
     212
     213        // Up to the SP to implement this lookup of keys. Possible ideas are:
     214        // (1) do a lookup in a table of trusted certs keyed off of consumer
     215        //
     216        // Either way should return a string representation of the certificate
     217        protected abstract function fetch_private_cert(&$request);
     218
     219        public function build_signature($request, $consumer, $token) {
     220                $base_string = $request->get_signature_base_string();
     221                $request->base_string = $base_string;
     222
     223                // Fetch the private key cert based on the request
     224                $cert = $this->fetch_private_cert($request);
     225
     226                // Pull the private key ID from the certificate
     227                $privatekeyid = openssl_get_privatekey($cert);
     228
     229                // Sign using the key
     230                $ok = openssl_sign($base_string, $signature, $privatekeyid);
     231
     232                // Release the key resource
     233                openssl_free_key($privatekeyid);
     234
     235                return base64_encode($signature);
     236        }
     237
     238        public function check_signature($request, $consumer, $token, $signature) {
     239                $decoded_sig = base64_decode($signature);
     240
     241                $base_string = $request->get_signature_base_string();
     242
     243                // Fetch the public key cert based on the request
     244                $cert = $this->fetch_public_cert($request);
     245
     246                // Pull the public key ID from the certificate
     247                $publickeyid = openssl_get_publickey($cert);
     248
     249                // Check the computed signature against the one passed in the query
     250                $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
     251
     252                // Release the key resource
     253                openssl_free_key($publickeyid);
     254
     255                return $ok == 1;
     256        }
    246257}
    247258
    248259class OAuthRequest {
    249   private $parameters;
    250   private $http_method;
    251   private $http_url;
    252   // for debug purposes
    253   public $base_string;
    254   public static $version = '1.0';
    255   public static $POST_INPUT = 'php://input';
    256 
    257   function __construct($http_method, $http_url, $parameters=NULL) {
    258     @$parameters or $parameters = array();
    259     $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
    260     $this->parameters = $parameters;
    261     $this->http_method = $http_method;
    262     $this->http_url = $http_url;
    263   }
    264 
    265 
    266   /**
    267    * attempt to build up a request from what was passed to the server
    268    */
    269   public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
    270     $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
    271               ? 'http'
    272               : 'https';
    273     @$http_url or $http_url = $scheme .
    274                               '://' . $_SERVER['HTTP_HOST'] .
    275                               ':' .
    276                               $_SERVER['SERVER_PORT'] .
    277                               $_SERVER['REQUEST_URI'];
    278     @$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
    279 
    280     // We weren't handed any parameters, so let's find the ones relevant to
    281     // this request.
    282     // If you run XML-RPC or similar you should use this to provide your own
    283     // parsed parameter-list
    284     if (!$parameters) {
    285       // Find request headers
    286       $request_headers = OAuthUtil::get_headers();
    287 
    288       // Parse the query-string to find GET parameters
    289       $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
    290 
    291       // It's a POST request of the proper content-type, so parse POST
    292       // parameters and add those overriding any duplicates from GET
    293       if ($http_method == "POST"
    294           && @strstr($request_headers["Content-Type"],
    295                      "application/x-www-form-urlencoded")
    296           ) {
    297         $post_data = OAuthUtil::parse_parameters(
    298           file_get_contents(self::$POST_INPUT)
    299         );
    300         $parameters = array_merge($parameters, $post_data);
    301       }
    302 
    303       // We have a Authorization-header with OAuth data. Parse the header
    304       // and add those overriding any duplicates from GET or POST
    305       if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
    306         $header_parameters = OAuthUtil::split_header(
    307           $request_headers['Authorization']
    308         );
    309         $parameters = array_merge($parameters, $header_parameters);
    310       }
    311 
    312     }
    313 
    314     return new OAuthRequest($http_method, $http_url, $parameters);
    315   }
    316 
    317   /**
    318    * pretty much a helper function to set up the request
    319    */
    320   public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
    321     @$parameters or $parameters = array();
    322     $defaults = array("oauth_version" => OAuthRequest::$version,
    323                       "oauth_nonce" => OAuthRequest::generate_nonce(),
    324                       "oauth_timestamp" => OAuthRequest::generate_timestamp(),
    325                       "oauth_consumer_key" => $consumer->key);
    326     if ($token)
    327       $defaults['oauth_token'] = $token->key;
    328 
    329     $parameters = array_merge($defaults, $parameters);
    330 
    331     return new OAuthRequest($http_method, $http_url, $parameters);
    332   }
    333 
    334   public function set_parameter($name, $value, $allow_duplicates = true) {
    335     if ($allow_duplicates && isset($this->parameters[$name])) {
    336       // We have already added parameter(s) with this name, so add to the list
    337       if (is_scalar($this->parameters[$name])) {
    338         // This is the first duplicate, so transform scalar (string)
    339         // into an array so we can add the duplicates
    340         $this->parameters[$name] = array($this->parameters[$name]);
    341       }
    342 
    343       $this->parameters[$name][] = $value;
    344     } else {
    345       $this->parameters[$name] = $value;
    346     }
    347   }
    348 
    349   public function get_parameter($name) {
    350     return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
    351   }
    352 
    353   public function get_parameters() {
    354     return $this->parameters;
    355   }
    356 
    357   public function unset_parameter($name) {
    358     unset($this->parameters[$name]);
    359   }
    360 
    361   /**
    362    * The request parameters, sorted and concatenated into a normalized string.
    363    * @return string
    364    */
    365   public function get_signable_parameters() {
    366     // Grab all parameters
    367     $params = $this->parameters;
    368 
    369     // Remove oauth_signature if present
    370     // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
    371     if (isset($params['oauth_signature'])) {
    372       unset($params['oauth_signature']);
    373     }
    374 
    375     return OAuthUtil::build_http_query($params);
    376   }
    377 
    378   /**
    379    * Returns the base string of this request
    380    *
    381    * The base string defined as the method, the url
    382    * and the parameters (normalized), each urlencoded
    383    * and the concated with &.
    384    */
    385   public function get_signature_base_string() {
    386     $parts = array(
    387       $this->get_normalized_http_method(),
    388       $this->get_normalized_http_url(),
    389       $this->get_signable_parameters()
    390     );
    391 
    392     $parts = OAuthUtil::urlencode_rfc3986($parts);
    393 
    394     return implode('&', $parts);
    395   }
    396 
    397   /**
    398    * just uppercases the http method
    399    */
    400   public function get_normalized_http_method() {
    401     return strtoupper($this->http_method);
    402   }
    403 
    404   /**
    405    * parses the url and rebuilds it to be
    406    * scheme://host/path
    407    */
    408   public function get_normalized_http_url() {
    409     $parts = parse_url($this->http_url);
    410 
    411     $port = @$parts['port'];
    412     $scheme = $parts['scheme'];
    413     $host = $parts['host'];
    414     $path = @$parts['path'];
    415 
    416     $port or $port = ($scheme == 'https') ? '443' : '80';
    417 
    418     if (($scheme == 'https' && $port != '443')
    419         || ($scheme == 'http' && $port != '80')) {
    420       $host = "$host:$port";
    421     }
    422     return "$scheme://$host$path";
    423   }
    424 
    425   /**
    426    * builds a url usable for a GET request
    427    */
    428   public function to_url() {
    429     $post_data = $this->to_postdata();
    430     $out = $this->get_normalized_http_url();
    431     if ($post_data) {
    432       $out .= '?'.$post_data;
    433     }
    434     return $out;
    435   }
    436 
    437   /**
    438    * builds the data one would send in a POST request
    439    */
    440   public function to_postdata() {
    441     return OAuthUtil::build_http_query($this->parameters);
    442   }
    443 
    444   /**
    445    * builds the Authorization: header
    446    */
    447   public function to_header($realm=null) {
    448     $first = true;
    449         if($realm) {
    450       $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
    451       $first = false;
    452     } else
    453       $out = 'Authorization: OAuth';
    454 
    455     $total = array();
    456     foreach ($this->parameters as $k => $v) {
    457       if (substr($k, 0, 5) != "oauth") continue;
    458       if (is_array($v)) {
    459         throw new OAuthException('Arrays not supported in headers');
    460       }
    461       $out .= ($first) ? ' ' : ',';
    462       $out .= OAuthUtil::urlencode_rfc3986($k) .
    463               '="' .
    464               OAuthUtil::urlencode_rfc3986($v) .
    465               '"';
    466       $first = false;
    467     }
    468     return $out;
    469   }
    470 
    471   public function __toString() {
    472     return $this->to_url();
    473   }
    474 
    475 
    476   public function sign_request($signature_method, $consumer, $token) {
    477     $this->set_parameter(
    478       "oauth_signature_method",
    479       $signature_method->get_name(),
    480       false
    481     );
    482     $signature = $this->build_signature($signature_method, $consumer, $token);
    483     $this->set_parameter("oauth_signature", $signature, false);
    484   }
    485 
    486   public function build_signature($signature_method, $consumer, $token) {
    487     $signature = $signature_method->build_signature($this, $consumer, $token);
    488     return $signature;
    489   }
    490 
    491   /**
    492    * util function: current timestamp
    493    */
    494   private static function generate_timestamp() {
    495     return time();
    496   }
    497 
    498   /**
    499    * util function: current nonce
    500    */
    501   private static function generate_nonce() {
    502     $mt = microtime();
    503     $rand = mt_rand();
    504 
    505     return md5($mt . $rand); // md5s look nicer than numbers
    506   }
     260        private $parameters;
     261        private $http_method;
     262        private $http_url;
     263        // for debug purposes
     264        public $base_string;
     265        public static $version = '1.0';
     266        public static $POST_INPUT = 'php://input';
     267
     268        function __construct($http_method, $http_url, $parameters = null) {
     269                @$parameters or $parameters = array();
     270                $parameters = array_merge(OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
     271                $this->parameters = $parameters;
     272                $this->http_method = $http_method;
     273                $this->http_url = $http_url;
     274        }
     275
     276
     277        /**
     278         * attempt to build up a request from what was passed to the server
     279         */
     280        public static function from_request($http_method = null, $http_url = null, $parameters = null) {
     281                $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
     282                        ? 'http'
     283                        : 'https';
     284                @$http_url or $http_url = $scheme .
     285                        '://' . $_SERVER['HTTP_HOST'] .
     286                        ':' .
     287                        $_SERVER['SERVER_PORT'] .
     288                        $_SERVER['REQUEST_URI'];
     289                @$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
     290
     291                // We weren't handed any parameters, so let's find the ones relevant to
     292                // this request.
     293                // If you run XML-RPC or similar you should use this to provide your own
     294                // parsed parameter-list
     295                if (!$parameters) {
     296                        // Find request headers
     297                        $request_headers = OAuthUtil::get_headers();
     298
     299                        // Parse the query-string to find GET parameters
     300                        $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
     301
     302                        // It's a POST request of the proper content-type, so parse POST
     303                        // parameters and add those overriding any duplicates from GET
     304                        if ($http_method == "POST"
     305                                && @strstr($request_headers["Content-Type"],
     306                                        "application/x-www-form-urlencoded")
     307                        ) {
     308                                $post_data = OAuthUtil::parse_parameters(
     309                                        file_get_contents(self::$POST_INPUT)
     310                                );
     311                                $parameters = array_merge($parameters, $post_data);
     312                        }
     313
     314                        // We have a Authorization-header with OAuth data. Parse the header
     315                        // and add those overriding any duplicates from GET or POST
     316                        if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
     317                                $header_parameters = OAuthUtil::split_header(
     318                                        $request_headers['Authorization']
     319                                );
     320                                $parameters = array_merge($parameters, $header_parameters);
     321                        }
     322
     323                }
     324
     325                return new OAuthRequest($http_method, $http_url, $parameters);
     326        }
     327
     328        /**
     329         * pretty much a helper function to set up the request
     330         */
     331        public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters = null) {
     332                @$parameters or $parameters = array();
     333                $defaults = array(
     334                        "oauth_version" => OAuthRequest::$version,
     335                        "oauth_nonce" => OAuthRequest::generate_nonce(),
     336                        "oauth_timestamp" => OAuthRequest::generate_timestamp(),
     337                        "oauth_consumer_key" => $consumer->key,
     338                );
     339                if ($token) {
     340                        $defaults['oauth_token'] = $token->key;
     341                }
     342
     343                $parameters = array_merge($defaults, $parameters);
     344
     345                return new OAuthRequest($http_method, $http_url, $parameters);
     346        }
     347
     348        public function set_parameter($name, $value, $allow_duplicates = true) {
     349                if ($allow_duplicates && isset($this->parameters[$name])) {
     350                        // We have already added parameter(s) with this name, so add to the list
     351                        if (is_scalar($this->parameters[$name])) {
     352                                // This is the first duplicate, so transform scalar (string)
     353                                // into an array so we can add the duplicates
     354                                $this->parameters[$name] = array($this->parameters[$name]);
     355                        }
     356
     357                        $this->parameters[$name][] = $value;
     358                } else {
     359                        $this->parameters[$name] = $value;
     360                }
     361        }
     362
     363        public function get_parameter($name) {
     364                return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
     365        }
     366
     367        public function get_parameters() {
     368                return $this->parameters;
     369        }
     370
     371        public function unset_parameter($name) {
     372                unset($this->parameters[$name]);
     373        }
     374
     375        /**
     376         * The request parameters, sorted and concatenated into a normalized string.
     377         *
     378         * @return string
     379         */
     380        public function get_signable_parameters() {
     381                // Grab all parameters
     382                $params = $this->parameters;
     383
     384                // Remove oauth_signature if present
     385                // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
     386                if (isset($params['oauth_signature'])) {
     387                        unset($params['oauth_signature']);
     388                }
     389
     390                return OAuthUtil::build_http_query($params);
     391        }
     392
     393        /**
     394         * Returns the base string of this request
     395         *
     396         * The base string defined as the method, the url
     397         * and the parameters (normalized), each urlencoded
     398         * and the concated with &.
     399         */
     400        public function get_signature_base_string() {
     401                $parts = array(
     402                        $this->get_normalized_http_method(),
     403                        $this->get_normalized_http_url(),
     404                        $this->get_signable_parameters(),
     405                );
     406
     407                $parts = OAuthUtil::urlencode_rfc3986($parts);
     408
     409                return implode('&', $parts);
     410        }
     411
     412        /**
     413         * just uppercases the http method
     414         */
     415        public function get_normalized_http_method() {
     416                return strtoupper($this->http_method);
     417        }
     418
     419        /**
     420         * parses the url and rebuilds it to be
     421         * scheme://host/path
     422         */
     423        public function get_normalized_http_url() {
     424                $parts = parse_url($this->http_url);
     425
     426                $port = @$parts['port'];
     427                $scheme = $parts['scheme'];
     428                $host = $parts['host'];
     429                $path = @$parts['path'];
     430
     431                $port or $port = ($scheme == 'https') ? '443' : '80';
     432
     433                if (($scheme == 'https' && $port != '443')
     434                        || ($scheme == 'http' && $port != '80')) {
     435                        $host = "$host:$port";
     436                }
     437
     438                return "$scheme://$host$path";
     439        }
     440
     441        /**
     442         * builds a url usable for a GET request
     443         */
     444        public function to_url() {
     445                $post_data = $this->to_postdata();
     446                $out = $this->get_normalized_http_url();
     447                if ($post_data) {
     448                        $out .= '?' . $post_data;
     449                }
     450
     451                return $out;
     452        }
     453
     454        /**
     455         * builds the data one would send in a POST request
     456         */
     457        public function to_postdata() {
     458                return OAuthUtil::build_http_query($this->parameters);
     459        }
     460
     461        /**
     462         * builds the Authorization: header
     463         */
     464        public function to_header($realm = null) {
     465                $first = true;
     466                if ($realm) {
     467                        $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
     468                        $first = false;
     469                } else {
     470                        $out = 'Authorization: OAuth';
     471                }
     472
     473                $total = array();
     474                foreach ($this->parameters as $k => $v) {
     475                        if (substr($k, 0, 5) != "oauth") {
     476                                continue;
     477                        }
     478                        if (is_array($v)) {
     479                                throw new OAuthException('Arrays not supported in headers');
     480                        }
     481                        $out .= ($first) ? ' ' : ',';
     482                        $out .= OAuthUtil::urlencode_rfc3986($k) .
     483                                '="' .
     484                                OAuthUtil::urlencode_rfc3986($v) .
     485                                '"';
     486                        $first = false;
     487                }
     488
     489                return $out;
     490        }
     491
     492        public function __toString() {
     493                return $this->to_url();
     494        }
     495
     496
     497        public function sign_request($signature_method, $consumer, $token) {
     498                $this->set_parameter(
     499                        "oauth_signature_method",
     500                        $signature_method->get_name(),
     501                        false
     502                );
     503                $signature = $this->build_signature($signature_method, $consumer, $token);
     504                $this->set_parameter("oauth_signature", $signature, false);
     505        }
     506
     507        public function build_signature($signature_method, $consumer, $token) {
     508                $signature = $signature_method->build_signature($this, $consumer, $token);
     509
     510                return $signature;
     511        }
     512
     513        /**
     514         * util function: current timestamp
     515         */
     516        private static function generate_timestamp() {
     517                return time();
     518        }
     519
     520        /**
     521         * util function: current nonce
     522         */
     523        private static function generate_nonce() {
     524                $mt = microtime();
     525                $rand = mt_rand();
     526
     527                return md5($mt . $rand); // md5s look nicer than numbers
     528        }
    507529}
    508530
    509531class OAuthServer {
    510   protected $timestamp_threshold = 300; // in seconds, five minutes
    511   protected $version = '1.0';             // hi blaine
    512   protected $signature_methods = array();
    513 
    514   protected $data_store;
    515 
    516   function __construct($data_store) {
    517     $this->data_store = $data_store;
    518   }
    519 
    520   public function add_signature_method($signature_method) {
    521     $this->signature_methods[$signature_method->get_name()] =
    522       $signature_method;
    523   }
    524 
    525   // high level functions
    526 
    527   /**
    528    * process a request_token request
    529    * returns the request token on success
    530    */
    531   public function fetch_request_token(&$request) {
    532     $this->get_version($request);
    533 
    534     $consumer = $this->get_consumer($request);
    535 
    536     // no token required for the initial token request
    537     $token = NULL;
    538 
    539     $this->check_signature($request, $consumer, $token);
    540 
    541     // Rev A change
    542     $callback = $request->get_parameter('oauth_callback');
    543     $new_token = $this->data_store->new_request_token($consumer, $callback);
    544 
    545     return $new_token;
    546   }
    547 
    548   /**
    549    * process an access_token request
    550    * returns the access token on success
    551    */
    552   public function fetch_access_token(&$request) {
    553     $this->get_version($request);
    554 
    555     $consumer = $this->get_consumer($request);
    556 
    557     // requires authorized request token
    558     $token = $this->get_token($request, $consumer, "request");
    559 
    560     $this->check_signature($request, $consumer, $token);
    561 
    562     // Rev A change
    563     $verifier = $request->get_parameter('oauth_verifier');
    564     $new_token = $this->data_store->new_access_token($token, $consumer, $verifier);
    565 
    566     return $new_token;
    567   }
    568 
    569   /**
    570    * verify an api call, checks all the parameters
    571    */
    572   public function verify_request(&$request) {
    573     $this->get_version($request);
    574     $consumer = $this->get_consumer($request);
    575     $token = $this->get_token($request, $consumer, "access");
    576     $this->check_signature($request, $consumer, $token);
    577     return array($consumer, $token);
    578   }
    579 
    580   // Internals from here
    581   /**
    582    * version 1
    583    */
    584   private function get_version(&$request) {
    585     $version = $request->get_parameter("oauth_version");
    586     if (!$version) {
    587       // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
    588       // Chapter 7.0 ("Accessing Protected Ressources")
    589       $version = '1.0';
    590     }
    591     if ($version !== $this->version) {
    592       throw new OAuthException("OAuth version '$version' not supported");
    593     }
    594     return $version;
    595   }
    596 
    597   /**
    598    * figure out the signature with some defaults
    599    */
    600   private function get_signature_method(&$request) {
    601     $signature_method =
    602         @$request->get_parameter("oauth_signature_method");
    603 
    604     if (!$signature_method) {
    605       // According to chapter 7 ("Accessing Protected Ressources") the signature-method
    606       // parameter is required, and we can't just fallback to PLAINTEXT
    607       throw new OAuthException('No signature method parameter. This parameter is required');
    608     }
    609 
    610     if (!in_array($signature_method,
    611                   array_keys($this->signature_methods))) {
    612       throw new OAuthException(
    613         "Signature method '$signature_method' not supported " .
    614         "try one of the following: " .
    615         implode(", ", array_keys($this->signature_methods))
    616       );
    617     }
    618     return $this->signature_methods[$signature_method];
    619   }
    620 
    621   /**
    622    * try to find the consumer for the provided request's consumer key
    623    */
    624   private function get_consumer(&$request) {
    625     $consumer_key = @$request->get_parameter("oauth_consumer_key");
    626     if (!$consumer_key) {
    627       throw new OAuthException("Invalid consumer key");
    628     }
    629 
    630     $consumer = $this->data_store->lookup_consumer($consumer_key);
    631     if (!$consumer) {
    632       throw new OAuthException("Invalid consumer");
    633     }
    634 
    635     return $consumer;
    636   }
    637 
    638   /**
    639    * try to find the token for the provided request's token key
    640    */
    641   private function get_token(&$request, $consumer, $token_type="access") {
    642     $token_field = @$request->get_parameter('oauth_token');
    643     $token = $this->data_store->lookup_token(
    644       $consumer, $token_type, $token_field
    645     );
    646     if (!$token) {
    647       throw new OAuthException("Invalid $token_type token: $token_field");
    648     }
    649     return $token;
    650   }
    651 
    652   /**
    653    * all-in-one function to check the signature on a request
    654    * should guess the signature method appropriately
    655    */
    656   private function check_signature(&$request, $consumer, $token) {
    657     // this should probably be in a different method
    658     $timestamp = @$request->get_parameter('oauth_timestamp');
    659     $nonce = @$request->get_parameter('oauth_nonce');
    660 
    661     $this->check_timestamp($timestamp);
    662     $this->check_nonce($consumer, $token, $nonce, $timestamp);
    663 
    664     $signature_method = $this->get_signature_method($request);
    665 
    666     $signature = $request->get_parameter('oauth_signature');
    667     $valid_sig = $signature_method->check_signature(
    668       $request,
    669       $consumer,
    670       $token,
    671       $signature
    672     );
    673 
    674     if (!$valid_sig) {
    675       throw new OAuthException("Invalid signature");
    676     }
    677   }
    678 
    679   /**
    680    * check that the timestamp is new enough
    681    */
    682   private function check_timestamp($timestamp) {
    683     if( ! $timestamp )
    684       throw new OAuthException(
    685         'Missing timestamp parameter. The parameter is required'
    686       );
    687    
    688     // verify that timestamp is recentish
    689     $now = time();
    690     if (abs($now - $timestamp) > $this->timestamp_threshold) {
    691       throw new OAuthException(
    692         "Expired timestamp, yours $timestamp, ours $now"
    693       );
    694     }
    695   }
    696 
    697   /**
    698    * check that the nonce is not repeated
    699    */
    700   private function check_nonce($consumer, $token, $nonce, $timestamp) {
    701     if( ! $nonce )
    702       throw new OAuthException(
    703         'Missing nonce parameter. The parameter is required'
    704       );
    705 
    706     // verify that the nonce is uniqueish
    707     $found = $this->data_store->lookup_nonce(
    708       $consumer,
    709       $token,
    710       $nonce,
    711       $timestamp
    712     );
    713     if ($found) {
    714       throw new OAuthException("Nonce already used: $nonce");
    715     }
    716   }
     532        protected $timestamp_threshold = 300; // in seconds, five minutes
     533        protected $version = '1.0';             // hi blaine
     534        protected $signature_methods = array();
     535
     536        protected $data_store;
     537
     538        function __construct($data_store) {
     539                $this->data_store = $data_store;
     540        }
     541
     542        public function add_signature_method($signature_method) {
     543                $this->signature_methods[$signature_method->get_name()] =
     544                        $signature_method;
     545        }
     546
     547        // high level functions
     548
     549        /**
     550         * process a request_token request
     551         * returns the request token on success
     552         */
     553        public function fetch_request_token(&$request) {
     554                $this->get_version($request);
     555
     556                $consumer = $this->get_consumer($request);
     557
     558                // no token required for the initial token request
     559                $token = null;
     560
     561                $this->check_signature($request, $consumer, $token);
     562
     563                // Rev A change
     564                $callback = $request->get_parameter('oauth_callback');
     565                $new_token = $this->data_store->new_request_token($consumer, $callback);
     566
     567                return $new_token;
     568        }
     569
     570        /**
     571         * process an access_token request
     572         * returns the access token on success
     573         */
     574        public function fetch_access_token(&$request) {
     575                $this->get_version($request);
     576
     577                $consumer = $this->get_consumer($request);
     578
     579                // requires authorized request token
     580                $token = $this->get_token($request, $consumer, "request");
     581
     582                $this->check_signature($request, $consumer, $token);
     583
     584                // Rev A change
     585                $verifier = $request->get_parameter('oauth_verifier');
     586                $new_token = $this->data_store->new_access_token($token, $consumer, $verifier);
     587
     588                return $new_token;
     589        }
     590
     591        /**
     592         * verify an api call, checks all the parameters
     593         */
     594        public function verify_request(&$request) {
     595                $this->get_version($request);
     596                $consumer = $this->get_consumer($request);
     597                $token = $this->get_token($request, $consumer, "access");
     598                $this->check_signature($request, $consumer, $token);
     599
     600                return array($consumer, $token);
     601        }
     602
     603        // Internals from here
     604
     605        /**
     606         * version 1
     607         */
     608        private function get_version(&$request) {
     609                $version = $request->get_parameter("oauth_version");
     610                if (!$version) {
     611                        // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
     612                        // Chapter 7.0 ("Accessing Protected Ressources")
     613                        $version = '1.0';
     614                }
     615                if ($version !== $this->version) {
     616                        throw new OAuthException("OAuth version '$version' not supported");
     617                }
     618
     619                return $version;
     620        }
     621
     622        /**
     623         * figure out the signature with some defaults
     624         */
     625        private function get_signature_method(&$request) {
     626                $signature_method =
     627                        @$request->get_parameter("oauth_signature_method");
     628
     629                if (!$signature_method) {
     630                        // According to chapter 7 ("Accessing Protected Ressources") the signature-method
     631                        // parameter is required, and we can't just fallback to PLAINTEXT
     632                        throw new OAuthException('No signature method parameter. This parameter is required');
     633                }
     634
     635                if (!in_array($signature_method,
     636                        array_keys($this->signature_methods))) {
     637                        throw new OAuthException(
     638                                "Signature method '$signature_method' not supported " .
     639                                "try one of the following: " .
     640                                implode(", ", array_keys($this->signature_methods))
     641                        );
     642                }
     643
     644                return $this->signature_methods[$signature_method];
     645        }
     646
     647        /**
     648         * try to find the consumer for the provided request's consumer key
     649         */
     650        private function get_consumer(&$request) {
     651                $consumer_key = @$request->get_parameter("oauth_consumer_key");
     652                if (!$consumer_key) {
     653                        throw new OAuthException("Invalid consumer key");
     654                }
     655
     656                $consumer = $this->data_store->lookup_consumer($consumer_key);
     657                if (!$consumer) {
     658                        throw new OAuthException("Invalid consumer");
     659                }
     660
     661                return $consumer;
     662        }
     663
     664        /**
     665         * try to find the token for the provided request's token key
     666         */
     667        private function get_token(&$request, $consumer, $token_type = "access") {
     668                $token_field = @$request->get_parameter('oauth_token');
     669                $token = $this->data_store->lookup_token(
     670                        $consumer, $token_type, $token_field
     671                );
     672                if (!$token) {
     673                        throw new OAuthException("Invalid $token_type token: $token_field");
     674                }
     675
     676                return $token;
     677        }
     678
     679        /**
     680         * all-in-one function to check the signature on a request
     681         * should guess the signature method appropriately
     682         */
     683        private function check_signature(&$request, $consumer, $token) {
     684                // this should probably be in a different method
     685                $timestamp = @$request->get_parameter('oauth_timestamp');
     686                $nonce = @$request->get_parameter('oauth_nonce');
     687
     688                $this->check_timestamp($timestamp);
     689                $this->check_nonce($consumer, $token, $nonce, $timestamp);
     690
     691                $signature_method = $this->get_signature_method($request);
     692
     693                $signature = $request->get_parameter('oauth_signature');
     694                $valid_sig = $signature_method->check_signature(
     695                        $request,
     696                        $consumer,
     697                        $token,
     698                        $signature
     699                );
     700
     701                if (!$valid_sig) {
     702                        throw new OAuthException("Invalid signature");
     703                }
     704        }
     705
     706        /**
     707         * check that the timestamp is new enough
     708         */
     709        private function check_timestamp($timestamp) {
     710                if (!$timestamp) {
     711                        throw new OAuthException(
     712                                'Missing timestamp parameter. The parameter is required'
     713                        );
     714                }
     715
     716                // verify that timestamp is recentish
     717                $now = time();
     718                if (abs($now - $timestamp) > $this->timestamp_threshold) {
     719                        throw new OAuthException(
     720                                "Expired timestamp, yours $timestamp, ours $now"
     721                        );
     722                }
     723        }
     724
     725        /**
     726         * check that the nonce is not repeated
     727         */
     728        private function check_nonce($consumer, $token, $nonce, $timestamp) {
     729                if (!$nonce) {
     730                        throw new OAuthException(
     731                                'Missing nonce parameter. The parameter is required'
     732                        );
     733                }
     734
     735                // verify that the nonce is uniqueish
     736                $found = $this->data_store->lookup_nonce(
     737                        $consumer,
     738                        $token,
     739                        $nonce,
     740                        $timestamp
     741                );
     742                if ($found) {
     743                        throw new OAuthException("Nonce already used: $nonce");
     744                }
     745        }
    717746
    718747}
    719748
    720749class OAuthDataStore {
    721   function lookup_consumer($consumer_key) {
    722     // implement me
    723   }
    724 
    725   function lookup_token($consumer, $token_type, $token) {
    726     // implement me
    727   }
    728 
    729   function lookup_nonce($consumer, $token, $nonce, $timestamp) {
    730     // implement me
    731   }
    732 
    733   function new_request_token($consumer, $callback = null) {
    734     // return a new token attached to this consumer
    735   }
    736 
    737   function new_access_token($token, $consumer, $verifier = null) {
    738     // return a new access token attached to this consumer
    739     // for the user associated with this token if the request token
    740     // is authorized
    741     // should also invalidate the request token
    742   }
     750        function lookup_consumer($consumer_key) {
     751                // implement me
     752        }
     753
     754        function lookup_token($consumer, $token_type, $token) {
     755                // implement me
     756        }
     757
     758        function lookup_nonce($consumer, $token, $nonce, $timestamp) {
     759                // implement me
     760        }
     761
     762        function new_request_token($consumer, $callback = null) {
     763                // return a new token attached to this consumer
     764        }
     765
     766        function new_access_token($token, $consumer, $verifier = null) {
     767                // return a new access token attached to this consumer
     768                // for the user associated with this token if the request token
     769                // is authorized
     770                // should also invalidate the request token
     771        }
    743772
    744773}
    745774
    746775class OAuthUtil {
    747   public static function urlencode_rfc3986($input) {
    748   if (is_array($input)) {
    749     return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
    750   } else if (is_scalar($input)) {
    751     return str_replace(
    752       '+',
    753       ' ',
    754       str_replace('%7E', '~', rawurlencode($input))
    755     );
    756   } else {
    757     return '';
    758   }
    759 }
    760 
    761 
    762   // This decode function isn't taking into consideration the above
    763   // modifications to the encoding process. However, this method doesn't
    764   // seem to be used anywhere so leaving it as is.
    765   public static function urldecode_rfc3986($string) {
    766     return urldecode($string);
    767   }
    768 
    769   // Utility function for turning the Authorization: header into
    770   // parameters, has to do some unescaping
    771   // Can filter out any non-oauth parameters if needed (default behaviour)
    772   public static function split_header($header, $only_allow_oauth_parameters = true) {
    773     $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
    774     $offset = 0;
    775     $params = array();
    776     while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
    777       $match = $matches[0];
    778       $header_name = $matches[2][0];
    779       $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0];
    780       if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) {
    781         $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content);
    782       }
    783       $offset = $match[1] + strlen($match[0]);
    784     }
    785 
    786     if (isset($params['realm'])) {
    787       unset($params['realm']);
    788     }
    789 
    790     return $params;
    791   }
    792 
    793   // helper to try to sort out headers for people who aren't running apache
    794   public static function get_headers() {
    795     if (function_exists('apache_request_headers')) {
    796       // we need this to get the actual Authorization: header
    797       // because apache tends to tell us it doesn't exist
    798       $headers = apache_request_headers();
    799 
    800       // sanitize the output of apache_request_headers because
    801       // we always want the keys to be Cased-Like-This and arh()
    802       // returns the headers in the same case as they are in the
    803       // request
    804       $out = array();
    805       foreach( $headers AS $key => $value ) {
    806         $key = str_replace(
    807             " ",
    808             "-",
    809             ucwords(strtolower(str_replace("-", " ", $key)))
    810           );
    811         $out[$key] = $value;
    812       }
    813     } else {
    814       // otherwise we don't have apache and are just going to have to hope
    815       // that $_SERVER actually contains what we need
    816       $out = array();
    817       if( isset($_SERVER['CONTENT_TYPE']) )
    818         $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
    819       if( isset($_ENV['CONTENT_TYPE']) )
    820         $out['Content-Type'] = $_ENV['CONTENT_TYPE'];
    821 
    822       foreach ($_SERVER as $key => $value) {
    823         if (substr($key, 0, 5) == "HTTP_") {
    824           // this is chaos, basically it is just there to capitalize the first
    825           // letter of every word that is not an initial HTTP and strip HTTP
    826           // code from przemek
    827           $key = str_replace(
    828             " ",
    829             "-",
    830             ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
    831           );
    832           $out[$key] = $value;
    833         }
    834       }
    835     }
    836     return $out;
    837   }
    838 
    839   // This function takes a input like a=b&a=c&d=e and returns the parsed
    840   // parameters like this
    841   // array('a' => array('b','c'), 'd' => 'e')
    842   public static function parse_parameters( $input ) {
    843     if (!isset($input) || !$input) return array();
    844 
    845     $pairs = explode('&', $input);
    846 
    847     $parsed_parameters = array();
    848     foreach ($pairs as $pair) {
    849       $split = explode('=', $pair, 2);
    850       $parameter = OAuthUtil::urldecode_rfc3986($split[0]);
    851       $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : '';
    852 
    853       if (isset($parsed_parameters[$parameter])) {
    854         // We have already recieved parameter(s) with this name, so add to the list
    855         // of parameters with this name
    856 
    857         if (is_scalar($parsed_parameters[$parameter])) {
    858           // This is the first duplicate, so transform scalar (string) into an array
    859           // so we can add the duplicates
    860           $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
    861         }
    862 
    863         $parsed_parameters[$parameter][] = $value;
    864       } else {
    865         $parsed_parameters[$parameter] = $value;
    866       }
    867     }
    868     return $parsed_parameters;
    869   }
    870 
    871   public static function build_http_query($params) {
    872     if (!$params) return '';
    873 
    874     // Urlencode both keys and values
    875     $keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
    876     $values = OAuthUtil::urlencode_rfc3986(array_values($params));
    877     $params = array_combine($keys, $values);
    878 
    879     // Parameters are sorted by name, using lexicographical byte value ordering.
    880     // Ref: Spec: 9.1.1 (1)
    881     uksort($params, 'strcmp');
    882 
    883     $pairs = array();
    884     foreach ($params as $parameter => $value) {
    885       if (is_array($value)) {
    886         // If two or more parameters share the same name, they are sorted by their value
    887         // Ref: Spec: 9.1.1 (1)
    888         natsort($value);
    889         foreach ($value as $duplicate_value) {
    890           $pairs[] = $parameter . '=' . $duplicate_value;
    891         }
    892       } else {
    893         $pairs[] = $parameter . '=' . $value;
    894       }
    895     }
    896     // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
    897     // Each name-value pair is separated by an '&' character (ASCII code 38)
    898     return implode('&', $pairs);
    899   }
    900 }
    901 
     776        public static function urlencode_rfc3986($input) {
     777                if (is_array($input)) {
     778                        return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
     779                } else {
     780                        if (is_scalar($input)) {
     781                                return str_replace(
     782                                        '+',
     783                                        ' ',
     784                                        str_replace('%7E', '~', rawurlencode($input))
     785                                );
     786                        } else {
     787                                return '';
     788                        }
     789                }
     790        }
     791
     792
     793        // This decode function isn't taking into consideration the above
     794        // modifications to the encoding process. However, this method doesn't
     795        // seem to be used anywhere so leaving it as is.
     796        public static function urldecode_rfc3986($string) {
     797                return urldecode($string);
     798        }
     799
     800        // Utility function for turning the Authorization: header into
     801        // parameters, has to do some unescaping
     802        // Can filter out any non-oauth parameters if needed (default behaviour)
     803        public static function split_header($header, $only_allow_oauth_parameters = true) {
     804                $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
     805                $offset = 0;
     806                $params = array();
     807                while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
     808                        $match = $matches[0];
     809                        $header_name = $matches[2][0];
     810                        $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0];
     811                        if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) {
     812                                $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content);
     813                        }
     814                        $offset = $match[1] + strlen($match[0]);
     815                }
     816
     817                if (isset($params['realm'])) {
     818                        unset($params['realm']);
     819                }
     820
     821                return $params;
     822        }
     823
     824        // helper to try to sort out headers for people who aren't running apache
     825        public static function get_headers() {
     826                if (function_exists('apache_request_headers')) {
     827                        // we need this to get the actual Authorization: header
     828                        // because apache tends to tell us it doesn't exist
     829                        $headers = apache_request_headers();
     830
     831                        // sanitize the output of apache_request_headers because
     832                        // we always want the keys to be Cased-Like-This and arh()
     833                        // returns the headers in the same case as they are in the
     834                        // request
     835                        $out = array();
     836                        foreach ($headers AS $key => $value) {
     837                                $key = str_replace(
     838                                        " ",
     839                                        "-",
     840                                        ucwords(strtolower(str_replace("-", " ", $key)))
     841                                );
     842                                $out[$key] = $value;
     843                        }
     844                } else {
     845                        // otherwise we don't have apache and are just going to have to hope
     846                        // that $_SERVER actually contains what we need
     847                        $out = array();
     848                        if (isset($_SERVER['CONTENT_TYPE'])) {
     849                                $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
     850                        }
     851                        if (isset($_ENV['CONTENT_TYPE'])) {
     852                                $out['Content-Type'] = $_ENV['CONTENT_TYPE'];
     853                        }
     854
     855                        foreach ($_SERVER as $key => $value) {
     856                                if (substr($key, 0, 5) == "HTTP_") {
     857                                        // this is chaos, basically it is just there to capitalize the first
     858                                        // letter of every word that is not an initial HTTP and strip HTTP
     859                                        // code from przemek
     860                                        $key = str_replace(
     861                                                " ",
     862                                                "-",
     863                                                ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
     864                                        );
     865                                        $out[$key] = $value;
     866                                }
     867                        }
     868                }
     869
     870                return $out;
     871        }
     872
     873        // This function takes a input like a=b&a=c&d=e and returns the parsed
     874        // parameters like this
     875        // array('a' => array('b','c'), 'd' => 'e')
     876        public static function parse_parameters($input) {
     877                if (!isset($input) || !$input) {
     878                        return array();
     879                }
     880
     881                $pairs = explode('&', $input);
     882
     883                $parsed_parameters = array();
     884                foreach ($pairs as $pair) {
     885                        $split = explode('=', $pair, 2);
     886                        $parameter = OAuthUtil::urldecode_rfc3986($split[0]);
     887                        $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : '';
     888
     889                        if (isset($parsed_parameters[$parameter])) {
     890                                // We have already recieved parameter(s) with this name, so add to the list
     891                                // of parameters with this name
     892
     893                                if (is_scalar($parsed_parameters[$parameter])) {
     894                                        // This is the first duplicate, so transform scalar (string) into an array
     895                                        // so we can add the duplicates
     896                                        $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
     897                                }
     898
     899                                $parsed_parameters[$parameter][] = $value;
     900                        } else {
     901                                $parsed_parameters[$parameter] = $value;
     902                        }
     903                }
     904
     905                return $parsed_parameters;
     906        }
     907
     908        public static function build_http_query($params) {
     909                if (!$params) {
     910                        return '';
     911                }
     912
     913                // Urlencode both keys and values
     914                $keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
     915                $values = OAuthUtil::urlencode_rfc3986(array_values($params));
     916                $params = array_combine($keys, $values);
     917
     918                // Parameters are sorted by name, using lexicographical byte value ordering.
     919                // Ref: Spec: 9.1.1 (1)
     920                uksort($params, 'strcmp');
     921
     922                $pairs = array();
     923                foreach ($params as $parameter => $value) {
     924                        if (is_array($value)) {
     925                                // If two or more parameters share the same name, they are sorted by their value
     926                                // Ref: Spec: 9.1.1 (1)
     927                                natsort($value);
     928                                foreach ($value as $duplicate_value) {
     929                                        $pairs[] = $parameter . '=' . $duplicate_value;
     930                                }
     931                        } else {
     932                                $pairs[] = $parameter . '=' . $value;
     933                        }
     934                }
     935                // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
     936                // Each name-value pair is separated by an '&' character (ASCII code 38)
     937                return implode('&', $pairs);
     938        }
     939}
     940
  • _plugins_/twitter/trunk/inc/json.php

    r106454 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315
    14 if ( !function_exists('json_decode') ){
    15         function json_decode($content, $assoc=false){
     16if (!function_exists('json_decode')) {
     17        function json_decode($content, $assoc = false) {
    1618                include_spip('services/json');
    17                 if ( $assoc ){
    18                                 $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
     19                if ($assoc) {
     20                        $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
    1921                } else {
    20                                 $json = new Services_JSON;
     22                        $json = new Services_JSON;
    2123                }
     24
    2225                return $json->decode($content);
    2326        }
    2427}
    2528
    26 if ( !function_exists('json_encode') ){
    27         function json_encode($content){
     29if (!function_exists('json_encode')) {
     30        function json_encode($content) {
    2831                include_spip('services/json');
    2932                $json = new Services_JSON;
     
    3336}
    3437
    35 include_once _DIR_RESTREINT.'inc/json.php';
     38include_once _DIR_RESTREINT . 'inc/json.php';
    3639
  • _plugins_/twitter/trunk/inc/microblog.php

    r73558 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315include_spip("inc/twitter");
     
    2022 * $service : quel service
    2123 * $api : si on est vraiment desespere :-)
    22  * $tokens : dans le cas de oAuth chez twitter pouvoir passer des tokens différents
    23  * de ceux de la conf générale du site
     24 * $tokens : dans le cas de oAuth chez twitter pouvoir passer des tokens diffrents
     25 * de ceux de la conf g�n�rale du site
    2426 */
    25 if (!function_exists('microblog')){
    26 function microblog($status, $user=null, $pass=null, $service=null, $api=null, $tokens=null){
    27         return tweet($status, $tokens);
     27if (!function_exists('microblog')) {
     28        function microblog($status, $user = null, $pass = null, $service = null, $api = null, $tokens = null) {
     29                return tweet($status, $tokens);
     30        }
    2831}
    29 }
  • _plugins_/twitter/trunk/inc/twitter.php

    r108837 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
    12 
    13 if (!defined("_TWITTER_API_CALL_MICROCACHE_DELAY")) define("_TWITTER_API_CALL_MICROCACHE_DELAY",180);
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
     14
     15if (!defined("_TWITTER_API_CALL_MICROCACHE_DELAY")) {
     16        define("_TWITTER_API_CALL_MICROCACHE_DELAY", 180);
     17}
    1418
    1519/**
    1620 * Envoyer un message sur Twitter
     21 *
    1722 * @param $status
    1823 * @param null $tokens
    1924 *   permet d'utiliser des tokens specifiques et pas ceux pre-configures
    2025 *   (voir twitter_connect)
     26 *
    2127 * @return bool|string
    2228 */
    23 function tweet($status, $tokens = null){
     29function tweet($status, $tokens = null) {
    2430        // Certains define prennent le pas sur le reste (mode TEST)
    2531        if (defined('_TEST_MICROBLOG_SERVICE')) {
    2632                if (_TEST_MICROBLOG_SERVICE == '') {
    27                         spip_log('microblog desactive par _TEST_MICROBLOG_SERVICE',"twitter"._LOG_INFO_IMPORTANTE);
     33                        spip_log('microblog desactive par _TEST_MICROBLOG_SERVICE', "twitter" . _LOG_INFO_IMPORTANTE);
     34
    2835                        return false;
    2936                }
     
    3643
    3744        // si pas d'api utilisable on sort
    38         if (!$oAuthConnection)
    39                 return false;
    40        
     45        if (!$oAuthConnection) {
     46                return false;
     47        }
     48
    4149        // Preparer le message (utf8 < 280 caracteres)
    4250        //$status = trim(preg_replace(',\s+,', ' ', $status));
     
    4755
    4856        if (!strlen($status)) {
    49                 spip_log('Rien a bloguer','twitter');
     57                spip_log('Rien a bloguer', 'twitter');
     58
    5059                return false;
    5160        }
     
    5463
    5564        // anti-begaiment
    56         $begaie = md5(serialize(array($tokens,$status)));
     65        $begaie = md5(serialize(array($tokens, $status)));
    5766        if ($begaie == $GLOBALS['meta']['twitter_begaie']) {
    58                 spip_log("begaie $status", 'twitter'._LOG_INFO_IMPORTANTE);
     67                spip_log("begaie $status", 'twitter' . _LOG_INFO_IMPORTANTE);
     68
    5969                return false;
    6070        }
     
    6373        $ret = 'ok';
    6474        $api = 'statuses/update';
    65         $oAuthConnection->post($api,$datas);
    66         if (200 != $oAuthConnection->http_code){
    67                 spip_log('Erreur '.$oAuthConnection->http_code,'twitter');
     75        $oAuthConnection->post($api, $datas);
     76        if (200 != $oAuthConnection->http_code) {
     77                spip_log('Erreur ' . $oAuthConnection->http_code, 'twitter');
    6878                $ret = false;
    6979        }
    7080
    7181        // noter l'envoi pour ne pas twitter 2 fois de suite la meme chose
    72         if ($ret)
     82        if ($ret) {
    7383                ecrire_meta('twitter_begaie', $begaie);
     84        }
    7485
    7586        return $ret;
     
    89100 * @return bool|TwitterOAuthSPIP
    90101 */
    91 function twitter_connect($tokens=null){
     102function twitter_connect($tokens = null) {
    92103        static $connection = null;
    93104
    94105        $t = md5(serialize($tokens));
    95         if (!isset($connection[$t])){
    96 
    97                 if($tokens = twitter_tokens($tokens)){
     106        if (!isset($connection[$t])) {
     107
     108                if ($tokens = twitter_tokens($tokens)) {
    98109                        // Cas de twitter et oAuth
    99110                        $t2 = md5(serialize($tokens));
     
    105116                                $tokens['twitter_token_secret']);
    106117
    107                         if(!$connection[$t2]) {
    108                                 spip_log('Erreur de connexion à twitter, verifier la configuration','twitter'._LOG_ERREUR);
     118                        if (!$connection[$t2]) {
     119                                spip_log('Erreur de connexion à twitter, verifier la configuration', 'twitter' . _LOG_ERREUR);
     120
    109121                                return false;
    110122                        }
    111                 }
    112                 else{
    113                         spip_log('Erreur de connexion à twitter, verifier la configuration','twitter'._LOG_ERREUR);
     123                } else {
     124                        spip_log('Erreur de connexion à twitter, verifier la configuration', 'twitter' . _LOG_ERREUR);
     125
    114126                        return false;
    115127                }
    116128        }
     129
    117130        return $connection[$t];
    118131}
     
    123136 *
    124137 * @param array $tokens
     138 *
    125139 * @return array
    126140 */
    127 function twitter_tokens($tokens=null){
     141function twitter_tokens($tokens = null) {
    128142        $cfg = @unserialize($GLOBALS['meta']['microblog']);
    129         if (!$cfg AND !$tokens) return false;
    130         if (!$cfg) $cfg = array();
    131 
    132         if(!is_array($tokens))
     143        if (!$cfg AND !$tokens) {
     144                return false;
     145        }
     146        if (!$cfg) {
     147                $cfg = array();
     148        }
     149
     150        if (!is_array($tokens)) {
    133151                $tokens = array();
     152        }
    134153
    135154        $t = array_intersect_key($tokens,
    136155                array(
    137                         'twitter_consumer_key'=>'',
    138                         'twitter_consumer_secret'=>'',
    139                         'twitter_account'=>'',
    140                         'twitter_token'=>'',
    141                         'twitter_token_secret'=>'',
     156                        'twitter_consumer_key' => '',
     157                        'twitter_consumer_secret' => '',
     158                        'twitter_account' => '',
     159                        'twitter_token' => '',
     160                        'twitter_token_secret' => '',
    142161                ));
    143162
    144         if (!isset($t['twitter_consumer_key']) OR !isset($t['twitter_consumer_secret'])){
     163        if (!isset($t['twitter_consumer_key']) OR !isset($t['twitter_consumer_secret'])) {
    145164                $t['twitter_consumer_key'] = $cfg['twitter_consumer_key'];
    146165                $t['twitter_consumer_secret'] = $cfg['twitter_consumer_secret'];
    147166        }
    148167
    149         if (!isset($t['twitter_token']) OR !isset($t['twitter_token_secret'])){
     168        if (!isset($t['twitter_token']) OR !isset($t['twitter_token_secret'])) {
    150169                $account = $cfg['default_account'];
    151                 if (isset($t['twitter_account']) AND isset($cfg['twitter_accounts'][$t['twitter_account']]))
     170                if (isset($t['twitter_account']) AND isset($cfg['twitter_accounts'][$t['twitter_account']])) {
    152171                        $account = $t['twitter_account'];
    153 
    154                 if (!isset($cfg['twitter_accounts'][$account]) AND isset($cfg['twitter_accounts'])){
     172                }
     173
     174                if (!isset($cfg['twitter_accounts'][$account]) AND isset($cfg['twitter_accounts'])) {
    155175                        $accounts = array_keys($cfg['twitter_accounts']);
    156176                        $account = reset($accounts);
    157177                }
    158178
    159                 if (isset($cfg['twitter_accounts'][$account])){
     179                if (isset($cfg['twitter_accounts'][$account])) {
    160180                        $t['twitter_token'] = $cfg['twitter_accounts'][$account]['token'];
    161181                        $t['twitter_token_secret'] = $cfg['twitter_accounts'][$account]['token_secret'];
    162182                }
    163183        }
    164         if(
     184        if (
    165185                isset($t['twitter_consumer_key'])
    166                   AND isset($t['twitter_consumer_secret'])
    167                   AND isset($t['twitter_token'])
    168                   AND isset($t['twitter_token_secret'])){
     186                AND isset($t['twitter_consumer_secret'])
     187                AND isset($t['twitter_token'])
     188                AND isset($t['twitter_token_secret'])) {
    169189                return $t;
    170190        }
     
    176196 * Fonction d'utilisation simple de l'API twitter oAuth
    177197 *
    178  * @param $command string : la commande à passer
    179  * @param $type string : le type de commande (get/post/delete)
    180  * @param $params array : les paramètres dans un array de la commande
     198 * @param $command        string : la commande à passer
     199 * @param $type           string : le type de commande (get/post/delete)
     200 * @param $params         array : les paramètres dans un array de la commande
    181201 * @param array $options
    182  *   bool force : true pour forcer la requete hors cache
    183  *   string return_type : le retour souhaité par défaut cela renverra la chaine ou l'array retourné par la commande.
     202 *                        bool force : true pour forcer la requete hors cache
     203 *                        string return_type : le retour souhaité par défaut cela renverra la chaine ou l'array retourné par la commande.
    184204 *                        Sinon on peut utiliser les valeurs http_code,http_info,url
    185205 *
     
    191211 *   twitter_token : token du compte a utiliser
    192212 *   twitter_token_secret : token secret du compte a utiliser
     213 *
    193214 * @return bool|string|array
    194215 */
    195 function twitter_api_call($command,$type='get',$params=array(),$options=null){
     216function twitter_api_call($command, $type = 'get', $params = array(), $options = null) {
    196217        include_spip('inc/microblog');
    197218
     
    201222                OR (isset($options['force']) AND $options['force'])
    202223                OR !include_spip("inc/memoization")
    203           OR !function_exists("cache_get")
    204           OR !$t = twitter_tokens($options)
    205           OR !$cache_key = "twitter_api_call-".md5(serialize(array($command,$params,$t)))
    206           OR !$res = cache_get($cache_key)
    207           OR $res['time']+_TWITTER_API_CALL_MICROCACHE_DELAY<$_SERVER['REQUEST_TIME']){
    208 
    209                 if ($connection = twitter_connect($options)){
     224                OR !function_exists("cache_get")
     225                OR !$t = twitter_tokens($options)
     226                OR !$cache_key = "twitter_api_call-" . md5(serialize(array($command, $params, $t)))
     227                OR !$res = cache_get($cache_key)
     228                OR $res['time'] + _TWITTER_API_CALL_MICROCACHE_DELAY < $_SERVER['REQUEST_TIME']) {
     229
     230                if ($connection = twitter_connect($options)) {
    210231
    211232                        $res = array();
    212                         switch($type){
     233                        switch ($type) {
    213234                                case 'post':
    214                                         $res['content'] = $connection->post($command,$params);
     235                                        $res['content'] = $connection->post($command, $params);
    215236                                        break;
    216237                                case 'delete':
    217                                         $res['content'] = $connection->delete($command,$params);
     238                                        $res['content'] = $connection->delete($command, $params);
    218239                                        break;
    219240                                case 'get':
    220241                                default:
    221                                         $res['content'] = $connection->get($command,$params);
     242                                        $res['content'] = $connection->get($command, $params);
    222243                                        break;
    223244                        }
     
    227248                        $res['time'] = $_SERVER['REQUEST_TIME'];
    228249
    229                         if ($cache_key)
    230                                 cache_set($cache_key,$res,_TWITTER_API_CALL_MICROCACHE_DELAY*2);
    231                 }
    232                 else {
    233                         if (!$res)
     250                        if ($cache_key) {
     251                                cache_set($cache_key, $res, _TWITTER_API_CALL_MICROCACHE_DELAY * 2);
     252                        }
     253                } else {
     254                        if (!$res) {
    234255                                return false;
    235                         spip_log("twitter_api_call:$command echec connexion, on utilise le cache perime","twitter".LOG_INFO_IMPORTANTE);
    236                 }
    237         }
    238 
    239         $retour = isset($options['return_type'])?$options['return_type']:'content';
    240         if (!isset($res[$retour]))
     256                        }
     257                        spip_log("twitter_api_call:$command echec connexion, on utilise le cache perime", "twitter" . LOG_INFO_IMPORTANTE);
     258                }
     259        }
     260
     261        $retour = isset($options['return_type']) ? $options['return_type'] : 'content';
     262        if (!isset($res[$retour])) {
    241263                $retour = 'content';
    242 
    243         switch($retour){
     264        }
     265
     266        switch ($retour) {
    244267                default:
    245268                        return $res[$retour];
     
    248271                                // recopie ?
    249272                                $copy = array();
    250                                 foreach($res['content'] as $key => $val){
     273                                foreach ($res['content'] as $key => $val) {
    251274                                        $copy[$key] = $val;
    252275                                }
     276
    253277                                return $copy;
    254278                        }
     279
    255280                        return $res['content'];
    256281                        break;
     
    260285/**
    261286 * Verifier que la config twitter est OK
     287 *
    262288 * @param bool $complete
    263289 *   verification complete de la connexion, avec requete chez Twitter (plus lent)
     290 *
    264291 * @return bool
    265292 */
    266 function twitter_verifier_config($complete = false){
    267         if (!$tokens = twitter_tokens())
    268                 return false;
    269         if ($complete){
    270                 if (!twitter_connect())
     293function twitter_verifier_config($complete = false) {
     294        if (!$tokens = twitter_tokens()) {
     295                return false;
     296        }
     297        if ($complete) {
     298                if (!twitter_connect()) {
    271299                        return false;
    272                 if (!$infos = twitter_api_call("account/verify_credentials"))
     300                }
     301                if (!$infos = twitter_api_call("account/verify_credentials")) {
    273302                        return false;
     303                }
    274304        }
    275305
  • _plugins_/twitter/trunk/inc/twitter_notifications.php

    r106454 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315/*
     
    1618
    1719function twitter_notifications($x) {
    18   include_spip('inc/filtres_mini');
    19   include_spip('inc/texte');
     20        include_spip('inc/filtres_mini');
     21        include_spip('inc/texte');
    2022
    2123        $status = null;
    2224        $cfg = @unserialize($GLOBALS['meta']['microblog']);
    23         switch($x['args']['quoi']) {
     25        switch ($x['args']['quoi']) {
    2426                case 'forumposte':      // post forums
    2527                        if ($cfg['evt_forumposte']
    26                         AND $id = intval($x['args']['id'])) {
     28                                AND $id = intval($x['args']['id'])) {
    2729                                // ne pas poster si le forum est valide et config forum valide activee
    28                                 if (sql_getfetsel("statut","spip_forum","id_forum=".intval($id))!="publie"
    29                                         OR !$cfg['evt_forumvalide']){
    30                                         $status = twitter_annonce('forumposte',array('id_forum'=>$id));
    31                                         twitter_envoyer_tweet($status,array('objet'=>'forum','id_objet'=>$id));
     30                                if (sql_getfetsel("statut", "spip_forum", "id_forum=" . intval($id)) != "publie"
     31                                        OR !$cfg['evt_forumvalide']) {
     32                                        $status = twitter_annonce('forumposte', array('id_forum' => $id));
     33                                        twitter_envoyer_tweet($status, array('objet' => 'forum', 'id_objet' => $id));
    3234                                }
    3335                        }
     
    3537                case 'forumvalide':      // forum valide
    3638                        if ($cfg['evt_forumvalide']
    37                         AND $id = intval($x['args']['id'])) {
    38                                 $status = twitter_annonce('forumvalide',array('id_forum'=>$id));
    39                                 twitter_envoyer_tweet($status,array('objet'=>'forum','id_objet'=>$id));
     39                                AND $id = intval($x['args']['id'])) {
     40                                $status = twitter_annonce('forumvalide', array('id_forum' => $id));
     41                                twitter_envoyer_tweet($status, array('objet' => 'forum', 'id_objet' => $id));
    4042                        }
    4143                        break;
    4244
    4345                case 'instituerarticle':    // publier | proposer articles
    44                 if ($id = intval($x['args']['id'])
    45                         AND (
    46                                 // publier
    47                                 ($cfg['evt_publierarticles']
    48                                         AND $x['args']['options']['statut'] == 'publie'
    49                                         AND $x['args']['options']['statut_ancien'] != 'publie'
    50                                         AND ($GLOBALS['meta']["post_dates"]=='oui'
    51                                                 OR strtotime($x['args']['options']['date'])<=time()
    52                                                 OR $cfg['evt_publierarticlesfutur']!='publication'
     46                        if ($id = intval($x['args']['id'])
     47                                AND (
     48                                        // publier
     49                                        ($cfg['evt_publierarticles']
     50                                                AND $x['args']['options']['statut'] == 'publie'
     51                                                AND $x['args']['options']['statut_ancien'] != 'publie'
     52                                                AND ($GLOBALS['meta']["post_dates"] == 'oui'
     53                                                        OR strtotime($x['args']['options']['date']) <= time()
     54                                                        OR $cfg['evt_publierarticlesfutur'] != 'publication'
     55                                                )
     56                                        )
     57                                        OR
     58                                        // proposer
     59                                        ($cfg['evt_proposerarticles']
     60                                                AND $x['args']['options']['statut'] == 'prop'
     61                                                AND $x['args']['options']['statut_ancien'] != 'publie'
    5362                                        )
    5463                                )
    55                         OR
    56                                 // proposer
    57                                 ($cfg['evt_proposerarticles']
    58                                 AND $x['args']['options']['statut'] == 'prop'
    59                                 AND $x['args']['options']['statut_ancien'] != 'publie'
    60                                 )
    61                         )
    62                 ) {
    63                         // si on utilise aussi le cron pour annoncer les articles post-dates
    64                         // noter ceux qui sont deja annonces ici (pour eviter double annonce)
    65                         if ($x['args']['options']['statut'] == 'publie'
    66                           AND $GLOBALS['meta']["post_dates"]=='non'
    67                                 AND $cfg['evt_publierarticlesfutur']=='publication'
    68                         ){
    69                                 include_spip('inc/meta');
    70                                 ecrire_meta('twitter_annonces',$GLOBALS['meta']['twitter_annonces'].','.$id);
     64                        ) {
     65                                // si on utilise aussi le cron pour annoncer les articles post-dates
     66                                // noter ceux qui sont deja annonces ici (pour eviter double annonce)
     67                                if ($x['args']['options']['statut'] == 'publie'
     68                                        AND $GLOBALS['meta']["post_dates"] == 'non'
     69                                        AND $cfg['evt_publierarticlesfutur'] == 'publication'
     70                                ) {
     71                                        include_spip('inc/meta');
     72                                        ecrire_meta('twitter_annonces', $GLOBALS['meta']['twitter_annonces'] . ',' . $id);
     73                                }
     74
     75                                // en cas d'attente, on note la date du plus vieux, et on ajoute l'attente
     76                                $heure = time() + 60;
     77                                if (($attente = 60 * intval($cfg['attente'])) > 0) {
     78                                        $vieux = $GLOBALS['meta']['twitter_vieux'];
     79                                        if ($vieux AND $vieux > $heure - $attente) {
     80                                                $heure = $vieux + $attente;
     81                                        }
     82                                        ecrire_meta('twitter_vieux', $heure);
     83                                }
     84
     85                                $status = twitter_annonce('instituerarticle', array('id_article' => $id));
     86                                twitter_envoyer_tweet($status, array('objet' => 'article', 'id_objet' => $id), $heure);
    7187                        }
    72 
    73                         // en cas d'attente, on note la date du plus vieux, et on ajoute l'attente
    74                         $heure = time()+60;
    75                         if (($attente = 60*intval($cfg['attente'])) > 0) {
    76                                 $vieux = $GLOBALS['meta']['twitter_vieux'];
    77                                 if ($vieux AND $vieux>$heure-$attente) {
    78                                         $heure = $vieux + $attente;
    79                                 }
    80                                 ecrire_meta('twitter_vieux', $heure);
    81                         }
    82 
    83                         $status = twitter_annonce('instituerarticle',array('id_article'=>$id));
    84                         twitter_envoyer_tweet($status,array('objet'=>'article','id_objet'=>$id), $heure);
    85                 }
    86                 break;
     88                        break;
    8789        }
    8890
     
    9092}
    9193
    92 function twitter_annonce($quoi,$contexte){
    93         return trim(recuperer_fond("modeles/microblog_$quoi",$contexte));
     94function twitter_annonce($quoi, $contexte) {
     95        return trim(recuperer_fond("modeles/microblog_$quoi", $contexte));
    9496}
    9597
    96 function twitter_envoyer_tweet($status,$liens=array(), $heure = null){
     98function twitter_envoyer_tweet($status, $liens = array(), $heure = null) {
    9799        // un status vide ne provoque pas d'envoi
    98100        if (!is_null($status) AND strlen($status)) {
    99                 if (!function_exists('job_queue_add')){
     101                if (!function_exists('job_queue_add')) {
    100102                        include_spip('inc/twitter');
    101103                        tweet($status);
    102                 }
    103                 else {
    104                         if ($heure === null)
     104                } else {
     105                        if ($heure === null) {
    105106                                $heure = time() + 60;
    106                         $id_job = job_queue_add('tweet',"Twitter : $status",array($status),'inc/twitter',true, $heure);
    107                         if ($liens)
    108                                 job_queue_link($id_job,$liens);
     107                        }
     108                        $id_job = job_queue_add('tweet', "Twitter : $status", array($status), 'inc/twitter', true, $heure);
     109                        if ($liens) {
     110                                job_queue_link($id_job, $liens);
     111                        }
    109112                }
    110113        }
  • _plugins_/twitter/trunk/inc/twitter_to_array.php

    r73571 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315
     
    1820        $command = $url['path'];
    1921        $params = array();
    20         parse_str($url['query'],$params);
     22        parse_str($url['query'], $params);
    2123
    22         if (!function_exists('twitter_api_call'))
     24        if (!function_exists('twitter_api_call')) {
    2325                include_spip("inc/twitter");
     26        }
    2427
    25         $res = twitter_api_call($command,'get',$params,$options);
     28        $res = twitter_api_call($command, 'get', $params, $options);
    2629
    2730        return $res;
  • _plugins_/twitter/trunk/inc/twitteroauth.php

    r81826 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315/*
     
    2426 */
    2527class TwitterOAuth {
    26   /* Contains the last HTTP status code returned. */
    27   public $http_code;
    28   /* Contains the last API call. */
    29   public $url;
    30   /* Set up the API root URL. */
    31   public $host = "https://api.twitter.com/1.1/";
    32   /* Set timeout default. */
    33   public $timeout = 30;
    34   /* Set connect timeout. */
    35   public $connecttimeout = 30;
    36   /* Verify SSL Cert. */
    37   public $ssl_verifypeer = FALSE;
    38   /* Respons format. */
    39   public $format = 'json';
    40   /* Decode returned json data. */
    41   public $decode_json = TRUE;
    42   /* Contains the last HTTP headers returned. */
    43   public $http_info;
    44   /* Set the useragnet. */
    45   public $useragent = 'TwitterOAuth v0.2.0-beta2';
    46   /* Immediately retry the API call if the response was not successful. */
    47   //public $retry = TRUE;
    48 
    49 
    50 
    51 
    52   /**
    53    * Set API URLS
    54    */
    55   function accessTokenURL()  { return 'https://api.twitter.com/oauth/access_token'; }
    56   function authenticateURL() { return 'https://api.twitter.com/oauth/authenticate'; }
    57   function authorizeURL()    { return 'https://api.twitter.com/oauth/authorize'; }
    58   function requestTokenURL() { return 'https://api.twitter.com/oauth/request_token'; }
    59 
    60   /**
    61    * Debug helpers
    62    */
    63   function lastStatusCode() { return $this->http_status; }
    64   function lastAPICall() { return $this->last_api_call; }
    65 
    66   /**
    67    * construct TwitterOAuth object
    68    */
    69   function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) {
    70     $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
    71     $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);
    72     if (!empty($oauth_token) && !empty($oauth_token_secret)) {
    73       $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret);
    74     } else {
    75       $this->token = NULL;
    76     }
    77   }
    78 
    79 
    80   /**
    81    * Get a request_token from Twitter
    82    *
    83    * @returns a key/value array containing oauth_token and oauth_token_secret
    84    */
    85   function getRequestToken($oauth_callback = NULL) {
    86     $parameters = array();
    87     if (!empty($oauth_callback)) {
    88       $parameters['oauth_callback'] = $oauth_callback;
    89     }
    90     $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters);
    91     $token = OAuthUtil::parse_parameters($request);
    92     $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
    93     return $token;
    94   }
    95 
    96   /**
    97    * Get the authorize URL
    98    *
    99    * @returns a string
    100    */
    101   function getAuthorizeURL($token, $sign_in_with_twitter = TRUE) {
    102     if (is_array($token)) {
    103       $token = $token['oauth_token'];
    104     }
    105     if (empty($sign_in_with_twitter)) {
    106       return $this->authorizeURL() . "?oauth_token={$token}";
    107     } else {
    108        return $this->authenticateURL() . "?oauth_token={$token}";
    109     }
    110   }
    111 
    112   /**
    113    * Exchange request token and secret for an access token and
    114    * secret, to sign API calls.
    115    *
    116    * @returns array("oauth_token" => "the-access-token",
    117    *                "oauth_token_secret" => "the-access-secret",
    118    *                "user_id" => "9436992",
    119    *                "screen_name" => "abraham")
    120    */
    121   function getAccessToken($oauth_verifier = FALSE) {
    122     $parameters = array();
    123     if (!empty($oauth_verifier)) {
    124       $parameters['oauth_verifier'] = $oauth_verifier;
    125     }
    126     $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters);
    127     $token = OAuthUtil::parse_parameters($request);
    128     $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
    129     return $token;
    130   }
    131 
    132   /**
    133    * One time exchange of username and password for access token and secret.
    134    *
    135    * @returns array("oauth_token" => "the-access-token",
    136    *                "oauth_token_secret" => "the-access-secret",
    137    *                "user_id" => "9436992",
    138    *                "screen_name" => "abraham",
    139    *                "x_auth_expires" => "0")
    140    */ 
    141   function getXAuthToken($username, $password) {
    142     $parameters = array();
    143     $parameters['x_auth_username'] = $username;
    144     $parameters['x_auth_password'] = $password;
    145     $parameters['x_auth_mode'] = 'client_auth';
    146     $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters);
    147     $token = OAuthUtil::parse_parameters($request);
    148     $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
    149     return $token;
    150   }
    151 
    152   /**
    153    * GET wrapper for oAuthRequest.
    154    */
    155   function get($url, $parameters = array()) {
    156     $response = $this->oAuthRequest($url, 'GET', $parameters);
    157         if ($this->format === 'json' && $this->decode_json) {
    158                 return json_decode($response,true);
    159     }
    160     return $response;
    161   }
    162  
    163   /**
    164    * POST wrapper for oAuthRequest.
    165    */
    166   function post($url, $parameters = array()) {
    167     $response = $this->oAuthRequest($url, 'POST', $parameters);
    168     if ($this->format === 'json' && $this->decode_json) {
    169       return json_decode($response);
    170     }
    171     return $response;
    172   }
    173 
    174   /**
    175    * DELETE wrapper for oAuthReqeust.
    176    */
    177   function delete($url, $parameters = array()) {
    178     $response = $this->oAuthRequest($url, 'DELETE', $parameters);
    179     if ($this->format === 'json' && $this->decode_json) {
    180       return json_decode($response);
    181     }
    182     return $response;
    183   }
    184 
    185   /**
    186    * Format and sign an OAuth / API request
    187    */
    188   function oAuthRequest($url, $method, $parameters) {
    189     if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) {
    190       $url = "{$this->host}{$url}.{$this->format}";
    191     }
    192     $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters);
    193     $request->sign_request($this->sha1_method, $this->consumer, $this->token);
    194     switch ($method) {
    195     case 'GET':
    196       return $this->http($request->to_url(), 'GET');
    197     default:
    198       return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata());
    199     }
    200   }
    201 
    202   /**
    203    * Make an HTTP request
    204    *
    205    * @return API results
    206    */
    207   function http($url, $method, $postfields = NULL) {
    208 
    209 
    210 
    211     $this->http_info = array();
    212           if (!function_exists("curl_init")
    213             OR !function_exists("curl_setopt")
    214             OR !function_exists("curl_exec")
    215           )
    216                   throw new OAuthException('cURL is missing');
    217 
    218     $ci = curl_init();
    219     /* Curl settings */
    220     curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
    221     curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
    222     curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
    223     curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
    224     curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));
    225     curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
    226     curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
    227     curl_setopt($ci, CURLOPT_HEADER, FALSE);
    228 
    229     switch ($method) {
    230       case 'POST':
    231         curl_setopt($ci, CURLOPT_POST, TRUE);
    232         if (!empty($postfields)) {
    233           curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
    234         }
    235         break;
    236       case 'DELETE':
    237         curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
    238         if (!empty($postfields)) {
    239           $url = "{$url}?{$postfields}";
    240         }
    241     }
    242 
    243     curl_setopt($ci, CURLOPT_URL, $url);
    244     $response = curl_exec($ci);
    245     $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
    246     $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
    247     $this->url = $url;
    248     curl_close ($ci);
    249     return $response;
    250   }
    251 
    252   /**
    253    * Get the header info to store.
    254    */
    255   function getHeader($ch, $header) {
    256     $i = strpos($header, ':');
    257     if (!empty($i)) {
    258       $key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
    259       $value = trim(substr($header, $i + 2));
    260       $this->http_header[$key] = $value;
    261     }
    262     return strlen($header);
    263   }
     28        /* Contains the last HTTP status code returned. */
     29        public $http_code;
     30        /* Contains the last API call. */
     31        public $url;
     32        /* Set up the API root URL. */
     33        public $host = "https://api.twitter.com/1.1/";
     34        /* Set timeout default. */
     35        public $timeout = 30;
     36        /* Set connect timeout. */
     37        public $connecttimeout = 30;
     38        /* Verify SSL Cert. */
     39        public $ssl_verifypeer = false;
     40        /* Respons format. */
     41        public $format = 'json';
     42        /* Decode returned json data. */
     43        public $decode_json = true;
     44        /* Contains the last HTTP headers returned. */
     45        public $http_info;
     46        /* Set the useragnet. */
     47        public $useragent = 'TwitterOAuth v0.2.0-beta2';
     48        /* Immediately retry the API call if the response was not successful. */
     49        //public $retry = TRUE;
     50
     51
     52        /**
     53         * Set API URLS
     54         */
     55        function accessTokenURL() { return 'https://api.twitter.com/oauth/access_token'; }
     56
     57        function authenticateURL() { return 'https://api.twitter.com/oauth/authenticate'; }
     58
     59        function authorizeURL() { return 'https://api.twitter.com/oauth/authorize'; }
     60
     61        function requestTokenURL() { return 'https://api.twitter.com/oauth/request_token'; }
     62
     63        /**
     64         * Debug helpers
     65         */
     66        function lastStatusCode() { return $this->http_status; }
     67
     68        function lastAPICall() { return $this->last_api_call; }
     69
     70        /**
     71         * construct TwitterOAuth object
     72         */
     73        function __construct($consumer_key, $consumer_secret, $oauth_token = null, $oauth_token_secret = null) {
     74                $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
     75                $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);
     76                if (!empty($oauth_token) && !empty($oauth_token_secret)) {
     77                        $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret);
     78                } else {
     79                        $this->token = null;
     80                }
     81        }
     82
     83
     84        /**
     85         * Get a request_token from Twitter
     86         *
     87         * @returns a key/value array containing oauth_token and oauth_token_secret
     88         */
     89        function getRequestToken($oauth_callback = null) {
     90                $parameters = array();
     91                if (!empty($oauth_callback)) {
     92                        $parameters['oauth_callback'] = $oauth_callback;
     93                }
     94                $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters);
     95                $token = OAuthUtil::parse_parameters($request);
     96                $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
     97
     98                return $token;
     99        }
     100
     101        /**
     102         * Get the authorize URL
     103         *
     104         * @returns a string
     105         */
     106        function getAuthorizeURL($token, $sign_in_with_twitter = true) {
     107                if (is_array($token)) {
     108                        $token = $token['oauth_token'];
     109                }
     110                if (empty($sign_in_with_twitter)) {
     111                        return $this->authorizeURL() . "?oauth_token={$token}";
     112                } else {
     113                        return $this->authenticateURL() . "?oauth_token={$token}";
     114                }
     115        }
     116
     117        /**
     118         * Exchange request token and secret for an access token and
     119         * secret, to sign API calls.
     120         *
     121         * @returns array("oauth_token" => "the-access-token",
     122         *                "oauth_token_secret" => "the-access-secret",
     123         *                "user_id" => "9436992",
     124         *                "screen_name" => "abraham")
     125         */
     126        function getAccessToken($oauth_verifier = false) {
     127                $parameters = array();
     128                if (!empty($oauth_verifier)) {
     129                        $parameters['oauth_verifier'] = $oauth_verifier;
     130                }
     131                $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters);
     132                $token = OAuthUtil::parse_parameters($request);
     133                $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
     134
     135                return $token;
     136        }
     137
     138        /**
     139         * One time exchange of username and password for access token and secret.
     140         *
     141         * @returns array("oauth_token" => "the-access-token",
     142         *                "oauth_token_secret" => "the-access-secret",
     143         *                "user_id" => "9436992",
     144         *                "screen_name" => "abraham",
     145         *                "x_auth_expires" => "0")
     146         */
     147        function getXAuthToken($username, $password) {
     148                $parameters = array();
     149                $parameters['x_auth_username'] = $username;
     150                $parameters['x_auth_password'] = $password;
     151                $parameters['x_auth_mode'] = 'client_auth';
     152                $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters);
     153                $token = OAuthUtil::parse_parameters($request);
     154                $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
     155
     156                return $token;
     157        }
     158
     159        /**
     160         * GET wrapper for oAuthRequest.
     161         */
     162        function get($url, $parameters = array()) {
     163                $response = $this->oAuthRequest($url, 'GET', $parameters);
     164                if ($this->format === 'json' && $this->decode_json) {
     165                        return json_decode($response, true);
     166                }
     167
     168                return $response;
     169        }
     170
     171        /**
     172         * POST wrapper for oAuthRequest.
     173         */
     174        function post($url, $parameters = array()) {
     175                $response = $this->oAuthRequest($url, 'POST', $parameters);
     176                if ($this->format === 'json' && $this->decode_json) {
     177                        return json_decode($response);
     178                }
     179
     180                return $response;
     181        }
     182
     183        /**
     184         * DELETE wrapper for oAuthReqeust.
     185         */
     186        function delete($url, $parameters = array()) {
     187                $response = $this->oAuthRequest($url, 'DELETE', $parameters);
     188                if ($this->format === 'json' && $this->decode_json) {
     189                        return json_decode($response);
     190                }
     191
     192                return $response;
     193        }
     194
     195        /**
     196         * Format and sign an OAuth / API request
     197         */
     198        function oAuthRequest($url, $method, $parameters) {
     199                if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) {
     200                        $url = "{$this->host}{$url}.{$this->format}";
     201                }
     202                $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters);
     203                $request->sign_request($this->sha1_method, $this->consumer, $this->token);
     204                switch ($method) {
     205                        case 'GET':
     206                                return $this->http($request->to_url(), 'GET');
     207                        default:
     208                                return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata());
     209                }
     210        }
     211
     212        /**
     213         * Make an HTTP request
     214         *
     215         * @return API results
     216         */
     217        function http($url, $method, $postfields = null) {
     218
     219
     220                $this->http_info = array();
     221                if (!function_exists("curl_init")
     222                        OR !function_exists("curl_setopt")
     223                        OR !function_exists("curl_exec")
     224                ) {
     225                        throw new OAuthException('cURL is missing');
     226                }
     227
     228                $ci = curl_init();
     229                /* Curl settings */
     230                curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
     231                curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
     232                curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
     233                curl_setopt($ci, CURLOPT_RETURNTRANSFER, true);
     234                curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));
     235                curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
     236                curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
     237                curl_setopt($ci, CURLOPT_HEADER, false);
     238
     239                switch ($method) {
     240                        case 'POST':
     241                                curl_setopt($ci, CURLOPT_POST, true);
     242                                if (!empty($postfields)) {
     243                                        curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
     244                                }
     245                                break;
     246                        case 'DELETE':
     247                                curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
     248                                if (!empty($postfields)) {
     249                                        $url = "{$url}?{$postfields}";
     250                                }
     251                }
     252
     253                curl_setopt($ci, CURLOPT_URL, $url);
     254                $response = curl_exec($ci);
     255                $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
     256                $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
     257                $this->url = $url;
     258                curl_close($ci);
     259
     260                return $response;
     261        }
     262
     263        /**
     264         * Get the header info to store.
     265         */
     266        function getHeader($ch, $header) {
     267                $i = strpos($header, ':');
     268                if (!empty($i)) {
     269                        $key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
     270                        $value = trim(substr($header, $i + 2));
     271                        $this->http_header[$key] = $value;
     272                }
     273
     274                return strlen($header);
     275        }
    264276}
  • _plugins_/twitter/trunk/inc/twitteroauthspip.php

    r81826 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315include_spip('inc/twitteroauth');
     
    1820class TwitterOAuthSPIP extends TwitterOAuth {
    1921
    20   /**
    21   * Make an HTTP request
    22   *
    23   * @return API results
    24   */
    25   function http($url, $method, $postfields = NULL) {
    26           // var_dump(parent::http($url, $method, $postfields));
    27           include_spip("inc/distant");
     22        /**
     23        * Make an HTTP request
     24        *
     25        * @return API results
     26        */
     27        function http($url, $method, $postfields = null) {
     28                // var_dump(parent::http($url, $method, $postfields));
     29                include_spip("inc/distant");
    2830
    29                 $taille_max = _INC_DISTANT_MAX_SIZE;
    30           $trans = false;
    31           $refuser_gz = false;
    32           $date_verif = '';
    33           $uri_referer = '';
    34           $datas = '';
    35           $boundary = '';
    36           $current = $url;
     31                $taille_max = _INC_DISTANT_MAX_SIZE;
     32                $trans = false;
     33                $refuser_gz = false;
     34                $date_verif = '';
     35                $uri_referer = '';
     36                $datas = '';
     37                $boundary = '';
     38                $current = $url;
    3739
    38           switch ($method) {
    39       case 'POST':
     40                switch ($method) {
     41                        case 'POST':
    4042                                if (!empty($postfields)) {
    41                                   if (is_string($postfields)){
    42                                     parse_str($postfields,$datas);
    43                                   }
    44                                   else
    45                                     $datas = $postfields;
     43                                        if (is_string($postfields)) {
     44                                                parse_str($postfields, $datas);
     45                                        } else {
     46                                                $datas = $postfields;
     47                                        }
    4648
    47                                   list($type, $postdata) = prepare_donnees_post($datas, $boundary);
    48                                   $datas = $type . 'Content-Length: ' . strlen($postdata) . "\r\n\r\n" . $postdata;
     49                                        list($type, $postdata) = prepare_donnees_post($datas, $boundary);
     50                                        $datas = $type . 'Content-Length: ' . strlen($postdata) . "\r\n\r\n" . $postdata;
    4951                                }
    5052                                break;
    51       case 'DELETE':
    52        if (!empty($postfields)) {
    53                $current = "{$current}?{$postfields}";
    54        }
     53                        case 'DELETE':
     54                                if (!empty($postfields)) {
     55                                        $current = "{$current}?{$postfields}";
     56                                }
    5557                }
    5658
    57           $this->http_info = array(
    58                   'url' => $current,
    59                   'http_code' => 0,
    60                   'content_type' => '',
    61                   'header_size' => 0,
    62                   'request_size' => 0,
    63                   'redirect_count' => 0,
    64           );
    65           $this->url = $current;
    66           $response = '';
     59                $this->http_info = array(
     60                        'url' => $current,
     61                        'http_code' => 0,
     62                        'content_type' => '',
     63                        'header_size' => 0,
     64                        'request_size' => 0,
     65                        'redirect_count' => 0,
     66                );
     67                $this->url = $current;
     68                $response = '';
    6769
    68                 // dix tentatives maximum en cas d'entetes 301...
    69                 for ($i = 0; $i<10; $i++){
    70                   $current = recuperer_lapage($current, $trans, $method, $taille_max, $datas, $refuser_gz, $date_verif, $uri_referer);
    71                         if (!$current) break;
    72                         if (is_array($current)){
    73                           break;
    74                         }
    75                   else
    76                           spip_log("recuperer page recommence sur $current");
    77                 }
     70                // dix tentatives maximum en cas d'entetes 301...
     71                for ($i = 0; $i < 10; $i++) {
     72                        $current = recuperer_lapage($current, $trans, $method, $taille_max, $datas, $refuser_gz, $date_verif, $uri_referer);
     73                        if (!$current) {
     74                                break;
     75                        }
     76                        if (is_array($current)) {
     77                                break;
     78                        } else {
     79                                spip_log("recuperer page recommence sur $current");
     80                        }
     81                }
    7882
    79           $this->info['redirect_count'] = $i;
    80           if (!$current){
    81                   $this->http_code = 500;
    82                   $this->info['http_code'] = 500;
    83                   if ($GLOBALS['meta']["http_proxy"])
    84                     return $response;
    85                   else
    86                     return parent::http($url, $method, $postfields);
    87           }
    88           if (!is_array($current)){
    89                   $this->http_code = 301;
    90                   $this->http_info['http_code'] = 301;
    91                   return $response;
    92           }
     83                $this->info['redirect_count'] = $i;
     84                if (!$current) {
     85                        $this->http_code = 500;
     86                        $this->info['http_code'] = 500;
     87                        if ($GLOBALS['meta']["http_proxy"]) {
     88                                return $response;
     89                        } else {
     90                                return parent::http($url, $method, $postfields);
     91                        }
     92                }
     93                if (!is_array($current)) {
     94                        $this->http_code = 301;
     95                        $this->http_info['http_code'] = 301;
    9396
    94           $this->http_code = 200;
    95           $this->http_info['http_code'] = 200;
    96     list($headers, $response) = $current;
     97                        return $response;
     98                }
    9799
    98           $this->http_info['header_size'] = strlen($headers);
    99           $this->http_info['request_size'] = strlen($response);
     100                $this->http_code = 200;
     101                $this->http_info['http_code'] = 200;
     102                list($headers, $response) = $current;
     103
     104                $this->http_info['header_size'] = strlen($headers);
     105                $this->http_info['request_size'] = strlen($response);
    100106
    101107
    102     return $response;
    103   }
     108                return $response;
     109        }
    104110
    105111}
  • _plugins_/twitter/trunk/services/json.php

    r106454 r113146  
    99 */
    1010
    11 if (!defined("_ECRIRE_INC_VERSION")) return;
     11if (!defined("_ECRIRE_INC_VERSION")) {
     12        return;
     13}
    1214
    1315/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
     
    7173 * Marker constant for Services_JSON::decode(), used to flag stack state
    7274 */
    73 define('SERVICES_JSON_SLICE',   1);
     75define('SERVICES_JSON_SLICE', 1);
    7476
    7577/**
    7678 * Marker constant for Services_JSON::decode(), used to flag stack state
    7779 */
    78 define('SERVICES_JSON_IN_STR',  2);
     80define('SERVICES_JSON_IN_STR', 2);
    7981
    8082/**
    8183 * Marker constant for Services_JSON::decode(), used to flag stack state
    8284 */
    83 define('SERVICES_JSON_IN_ARR',  3);
     85define('SERVICES_JSON_IN_ARR', 3);
    8486
    8587/**
    8688 * Marker constant for Services_JSON::decode(), used to flag stack state
    8789 */
    88 define('SERVICES_JSON_IN_OBJ',  4);
     90define('SERVICES_JSON_IN_OBJ', 4);
    8991
    9092/**
     
    124126 * </code>
    125127 */
    126 class Services_JSON
    127 {
    128    /**
    129     * constructs a new JSON instance
    130     *
    131     * @param    int     $use    object behavior flags; combine with boolean-OR
    132     *
    133     *                           possible values:
    134     *                           - SERVICES_JSON_LOOSE_TYPE:  loose typing.
    135     *                                   "{...}" syntax creates associative arrays
    136     *                                   instead of objects in decode().
    137     *                           - SERVICES_JSON_SUPPRESS_ERRORS:  error suppression.
    138     *                                   Values which can't be encoded (e.g. resources)
    139     *                                   appear as NULL instead of throwing errors.
    140     *                                   By default, a deeply-nested resource will
    141     *                                   bubble up with an error, so all return values
    142     *                                   from encode() should be checked with isError()
    143     */
    144     function Services_JSON($use = 0)
    145     {
    146         $this->use = $use;
    147     }
    148 
    149    /**
    150     * convert a string from one UTF-16 char to one UTF-8 char
    151     *
    152     * Normally should be handled by mb_convert_encoding, but
    153     * provides a slower PHP-only method for installations
    154     * that lack the multibye string extension.
    155     *
    156     * @param    string  $utf16  UTF-16 character
    157     * @return   string  UTF-8 character
    158     * @access   private
    159     */
    160     function utf162utf8($utf16)
    161     {
    162         // oh please oh please oh please oh please oh please
    163         if(function_exists('mb_convert_encoding')) {
    164             return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
    165         }
    166 
    167         $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
    168 
    169         switch(true) {
    170             case ((0x7F & $bytes) == $bytes):
    171                 // this case should never be reached, because we are in ASCII range
    172                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    173                 return chr(0x7F & $bytes);
    174 
    175             case (0x07FF & $bytes) == $bytes:
    176                 // return a 2-byte UTF-8 character
    177                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    178                 return chr(0xC0 | (($bytes >> 6) & 0x1F))
    179                      . chr(0x80 | ($bytes & 0x3F));
    180 
    181             case (0xFFFF & $bytes) == $bytes:
    182                 // return a 3-byte UTF-8 character
    183                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    184                 return chr(0xE0 | (($bytes >> 12) & 0x0F))
    185                      . chr(0x80 | (($bytes >> 6) & 0x3F))
    186                      . chr(0x80 | ($bytes & 0x3F));
    187         }
    188 
    189         // ignoring UTF-32 for now, sorry
    190         return '';
    191     }
    192 
    193    /**
    194     * convert a string from one UTF-8 char to one UTF-16 char
    195     *
    196     * Normally should be handled by mb_convert_encoding, but
    197     * provides a slower PHP-only method for installations
    198     * that lack the multibye string extension.
    199     *
    200     * @param    string  $utf8   UTF-8 character
    201     * @return   string  UTF-16 character
    202     * @access   private
    203     */
    204     function utf82utf16($utf8)
    205     {
    206         // oh please oh please oh please oh please oh please
    207         if(function_exists('mb_convert_encoding')) {
    208             return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
    209         }
    210 
    211         switch(strlen($utf8)) {
    212             case 1:
    213                 // this case should never be reached, because we are in ASCII range
    214                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    215                 return $utf8;
    216 
    217             case 2:
    218                 // return a UTF-16 character from a 2-byte UTF-8 char
    219                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    220                 return chr(0x07 & (ord($utf8{0}) >> 2))
    221                      . chr((0xC0 & (ord($utf8{0}) << 6))
    222                          | (0x3F & ord($utf8{1})));
    223 
    224             case 3:
    225                 // return a UTF-16 character from a 3-byte UTF-8 char
    226                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    227                 return chr((0xF0 & (ord($utf8{0}) << 4))
    228                          | (0x0F & (ord($utf8{1}) >> 2)))
    229                      . chr((0xC0 & (ord($utf8{1}) << 6))
    230                          | (0x7F & ord($utf8{2})));
    231         }
    232 
    233         // ignoring UTF-32 for now, sorry
    234         return '';
    235     }
    236 
    237    /**
    238     * encodes an arbitrary variable into JSON format
    239     *
    240     * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
    241     *                           see argument 1 to Services_JSON() above for array-parsing behavior.
    242     *                           if var is a strng, note that encode() always expects it
    243     *                           to be in ASCII or UTF-8 format!
    244     *
    245     * @return   mixed   JSON string representation of input var or an error if a problem occurs
    246     * @access   public
    247     */
    248     function encode($var)
    249     {
    250         switch (gettype($var)) {
    251             case 'boolean':
    252                 return $var ? 'true' : 'false';
    253 
    254             case 'NULL':
    255                 return 'null';
    256 
    257             case 'integer':
    258                 return (int) $var;
    259 
    260             case 'double':
    261             case 'float':
    262                 return (float) $var;
    263 
    264             case 'string':
    265                 // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
    266                 $ascii = '';
    267                 $strlen_var = strlen($var);
    268 
    269                /*
    270                 * Iterate over every character in the string,
    271                 * escaping with a slash or encoding to UTF-8 where necessary
    272                 */
    273                 for ($c = 0; $c < $strlen_var; ++$c) {
    274 
    275                     $ord_var_c = ord($var{$c});
    276 
    277                     switch (true) {
    278                         case $ord_var_c == 0x08:
    279                             $ascii .= '\b';
    280                             break;
    281                         case $ord_var_c == 0x09:
    282                             $ascii .= '\t';
    283                             break;
    284                         case $ord_var_c == 0x0A:
    285                             $ascii .= '\n';
    286                             break;
    287                         case $ord_var_c == 0x0C:
    288                             $ascii .= '\f';
    289                             break;
    290                         case $ord_var_c == 0x0D:
    291                             $ascii .= '\r';
    292                             break;
    293 
    294                         case $ord_var_c == 0x22:
    295                         case $ord_var_c == 0x2F:
    296                         case $ord_var_c == 0x5C:
    297                             // double quote, slash, slosh
    298                             $ascii .= '\\'.$var{$c};
    299                             break;
    300 
    301                         case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
    302                             // characters U-00000000 - U-0000007F (same as ASCII)
    303                             $ascii .= $var{$c};
    304                             break;
    305 
    306                         case (($ord_var_c & 0xE0) == 0xC0):
    307                             // characters U-00000080 - U-000007FF, mask 110XXXXX
    308                             // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    309                             $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
    310                             $c += 1;
    311                             $utf16 = $this->utf82utf16($char);
    312                             $ascii .= sprintf('\u%04s', bin2hex($utf16));
    313                             break;
    314 
    315                         case (($ord_var_c & 0xF0) == 0xE0):
    316                             // characters U-00000800 - U-0000FFFF, mask 1110XXXX
    317                             // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    318                             $char = pack('C*', $ord_var_c,
    319                                          ord($var{$c + 1}),
    320                                          ord($var{$c + 2}));
    321                             $c += 2;
    322                             $utf16 = $this->utf82utf16($char);
    323                             $ascii .= sprintf('\u%04s', bin2hex($utf16));
    324                             break;
    325 
    326                         case (($ord_var_c & 0xF8) == 0xF0):
    327                             // characters U-00010000 - U-001FFFFF, mask 11110XXX
    328                             // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    329                             $char = pack('C*', $ord_var_c,
    330                                          ord($var{$c + 1}),
    331                                          ord($var{$c + 2}),
    332                                          ord($var{$c + 3}));
    333                             $c += 3;
    334                             $utf16 = $this->utf82utf16($char);
    335                             $ascii .= sprintf('\u%04s', bin2hex($utf16));
    336                             break;
    337 
    338                         case (($ord_var_c & 0xFC) == 0xF8):
    339                             // characters U-00200000 - U-03FFFFFF, mask 111110XX
    340                             // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    341                             $char = pack('C*', $ord_var_c,
    342                                          ord($var{$c + 1}),
    343                                          ord($var{$c + 2}),
    344                                          ord($var{$c + 3}),
    345                                          ord($var{$c + 4}));
    346                             $c += 4;
    347                             $utf16 = $this->utf82utf16($char);
    348                             $ascii .= sprintf('\u%04s', bin2hex($utf16));
    349                             break;
    350 
    351                         case (($ord_var_c & 0xFE) == 0xFC):
    352                             // characters U-04000000 - U-7FFFFFFF, mask 1111110X
    353                             // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    354                             $char = pack('C*', $ord_var_c,
    355                                          ord($var{$c + 1}),
    356                                          ord($var{$c + 2}),
    357                                          ord($var{$c + 3}),
    358                                          ord($var{$c + 4}),
    359                                          ord($var{$c + 5}));
    360                             $c += 5;
    361                             $utf16 = $this->utf82utf16($char);
    362                             $ascii .= sprintf('\u%04s', bin2hex($utf16));
    363                             break;
    364                     }
    365                 }
    366 
    367                 return '"'.$ascii.'"';
    368 
    369             case 'array':
    370                /*
    371                 * As per JSON spec if any array key is not an integer
    372                 * we must treat the the whole array as an object. We
    373                 * also try to catch a sparsely populated associative
    374                 * array with numeric keys here because some JS engines
    375                 * will create an array with empty indexes up to
    376                 * max_index which can cause memory issues and because
    377                 * the keys, which may be relevant, will be remapped
    378                 * otherwise.
    379                 *
    380                 * As per the ECMA and JSON specification an object may
    381                 * have any string as a property. Unfortunately due to
    382                 * a hole in the ECMA specification if the key is a
    383                 * ECMA reserved word or starts with a digit the
    384                 * parameter is only accessible using ECMAScript's
    385                 * bracket notation.
    386                 */
    387 
    388                 // treat as a JSON object
    389                 if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
    390                     $properties = array_map(array($this, 'name_value'),
    391                                             array_keys($var),
    392                                             array_values($var));
    393 
    394                     foreach($properties as $property) {
    395                         if(Services_JSON::isError($property)) {
    396                             return $property;
    397                         }
    398                     }
    399 
    400                     return '{' . join(',', $properties) . '}';
    401                 }
    402 
    403                 // treat it like a regular array
    404                 $elements = array_map(array($this, 'encode'), $var);
    405 
    406                 foreach($elements as $element) {
    407                     if(Services_JSON::isError($element)) {
    408                         return $element;
    409                     }
    410                 }
    411 
    412                 return '[' . join(',', $elements) . ']';
    413 
    414             case 'object':
    415                 $vars = get_object_vars($var);
    416 
    417                 $properties = array_map(array($this, 'name_value'),
    418                                         array_keys($vars),
    419                                         array_values($vars));
    420 
    421                 foreach($properties as $property) {
    422                     if(Services_JSON::isError($property)) {
    423                         return $property;
    424                     }
    425                 }
    426 
    427                 return '{' . join(',', $properties) . '}';
    428 
    429             default:
    430                 return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
    431                     ? 'null'
    432                     : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
    433         }
    434     }
    435 
    436    /**
    437     * array-walking function for use in generating JSON-formatted name-value pairs
    438     *
    439     * @param    string  $name   name of key to use
    440     * @param    mixed   $value  reference to an array element to be encoded
    441     *
    442     * @return   string  JSON-formatted name-value pair, like '"name":value'
    443     * @access   private
    444     */
    445     function name_value($name, $value)
    446     {
    447         $encoded_value = $this->encode($value);
    448 
    449         if(Services_JSON::isError($encoded_value)) {
    450             return $encoded_value;
    451         }
    452 
    453         return $this->encode(strval($name)) . ':' . $encoded_value;
    454     }
    455 
    456    /**
    457     * reduce a string by removing leading and trailing comments and whitespace
    458     *
    459     * @param    $str    string      string value to strip of comments and whitespace
    460     *
    461     * @return   string  string value stripped of comments and whitespace
    462     * @access   private
    463     */
    464     function reduce_string($str)
    465     {
    466         $str = preg_replace(array(
    467 
    468                 // eliminate single line comments in '// ...' form
    469                 '#^\s*//(.+)$#m',
    470 
    471                 // eliminate multi-line comments in '/* ... */' form, at start of string
    472                 '#^\s*/\*(.+)\*/#Us',
    473 
    474                 // eliminate multi-line comments in '/* ... */' form, at end of string
    475                 '#/\*(.+)\*/\s*$#Us'
    476 
    477             ), '', $str);
    478 
    479         // eliminate extraneous space
    480         return trim($str);
    481     }
    482 
    483    /**
    484     * decodes a JSON string into appropriate variable
    485     *
    486     * @param    string  $str    JSON-formatted string
    487     *
    488     * @return   mixed   number, boolean, string, array, or object
    489     *                   corresponding to given JSON input string.
    490     *                   See argument 1 to Services_JSON() above for object-output behavior.
    491     *                   Note that decode() always returns strings
    492     *                   in ASCII or UTF-8 format!
    493     * @access   public
    494     */
    495     function decode($str)
    496     {
    497         $str = $this->reduce_string($str);
    498 
    499         switch (strtolower($str)) {
    500             case 'true':
    501                 return true;
    502 
    503             case 'false':
    504                 return false;
    505 
    506             case 'null':
    507                 return null;
    508 
    509             default:
    510                 $m = array();
    511 
    512                 if (is_numeric($str)) {
    513                     // Lookie-loo, it's a number
    514 
    515                     // This would work on its own, but I'm trying to be
    516                     // good about returning integers where appropriate:
    517                     // return (float)$str;
    518 
    519                     // Return float or int, as appropriate
    520                     return ((float)$str == (integer)$str)
    521                         ? (integer)$str
    522                         : (float)$str;
    523 
    524                 } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
    525                     // STRINGS RETURNED IN UTF-8 FORMAT
    526                     $delim = substr($str, 0, 1);
    527                     $chrs = substr($str, 1, -1);
    528                     $utf8 = '';
    529                     $strlen_chrs = strlen($chrs);
    530 
    531                     for ($c = 0; $c < $strlen_chrs; ++$c) {
    532 
    533                         $substr_chrs_c_2 = substr($chrs, $c, 2);
    534                         $ord_chrs_c = ord($chrs{$c});
    535 
    536                         switch (true) {
    537                             case $substr_chrs_c_2 == '\b':
    538                                 $utf8 .= chr(0x08);
    539                                 ++$c;
    540                                 break;
    541                             case $substr_chrs_c_2 == '\t':
    542                                 $utf8 .= chr(0x09);
    543                                 ++$c;
    544                                 break;
    545                             case $substr_chrs_c_2 == '\n':
    546                                 $utf8 .= chr(0x0A);
    547                                 ++$c;
    548                                 break;
    549                             case $substr_chrs_c_2 == '\f':
    550                                 $utf8 .= chr(0x0C);
    551                                 ++$c;
    552                                 break;
    553                             case $substr_chrs_c_2 == '\r':
    554                                 $utf8 .= chr(0x0D);
    555                                 ++$c;
    556                                 break;
    557 
    558                             case $substr_chrs_c_2 == '\\"':
    559                             case $substr_chrs_c_2 == '\\\'':
    560                             case $substr_chrs_c_2 == '\\\\':
    561                             case $substr_chrs_c_2 == '\\/':
    562                                 if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
    563                                    ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
    564                                     $utf8 .= $chrs{++$c};
    565                                 }
    566                                 break;
    567 
    568                             case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
    569                                 // single, escaped unicode character
    570                                 $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
    571                                        . chr(hexdec(substr($chrs, ($c + 4), 2)));
    572                                 $utf8 .= $this->utf162utf8($utf16);
    573                                 $c += 5;
    574                                 break;
    575 
    576                             case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
    577                                 $utf8 .= $chrs{$c};
    578                                 break;
    579 
    580                             case ($ord_chrs_c & 0xE0) == 0xC0:
    581                                 // characters U-00000080 - U-000007FF, mask 110XXXXX
    582                                 //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    583                                 $utf8 .= substr($chrs, $c, 2);
    584                                 ++$c;
    585                                 break;
    586 
    587                             case ($ord_chrs_c & 0xF0) == 0xE0:
    588                                 // characters U-00000800 - U-0000FFFF, mask 1110XXXX
    589                                 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    590                                 $utf8 .= substr($chrs, $c, 3);
    591                                 $c += 2;
    592                                 break;
    593 
    594                             case ($ord_chrs_c & 0xF8) == 0xF0:
    595                                 // characters U-00010000 - U-001FFFFF, mask 11110XXX
    596                                 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    597                                 $utf8 .= substr($chrs, $c, 4);
    598                                 $c += 3;
    599                                 break;
    600 
    601                             case ($ord_chrs_c & 0xFC) == 0xF8:
    602                                 // characters U-00200000 - U-03FFFFFF, mask 111110XX
    603                                 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    604                                 $utf8 .= substr($chrs, $c, 5);
    605                                 $c += 4;
    606                                 break;
    607 
    608                             case ($ord_chrs_c & 0xFE) == 0xFC:
    609                                 // characters U-04000000 - U-7FFFFFFF, mask 1111110X
    610                                 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    611                                 $utf8 .= substr($chrs, $c, 6);
    612                                 $c += 5;
    613                                 break;
    614 
    615                         }
    616 
    617                     }
    618 
    619                     return $utf8;
    620 
    621                 } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
    622                     // array, or object notation
    623 
    624                     if ($str{0} == '[') {
    625                         $stk = array(SERVICES_JSON_IN_ARR);
    626                         $arr = array();
    627                     } else {
    628                         if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
    629                             $stk = array(SERVICES_JSON_IN_OBJ);
    630                             $obj = array();
    631                         } else {
    632                             $stk = array(SERVICES_JSON_IN_OBJ);
    633                             $obj = new stdClass();
    634                         }
    635                     }
    636 
    637                     array_push($stk, array('what'  => SERVICES_JSON_SLICE,
    638                                            'where' => 0,
    639                                            'delim' => false));
    640 
    641                     $chrs = substr($str, 1, -1);
    642                     $chrs = $this->reduce_string($chrs);
    643 
    644                     if ($chrs == '') {
    645                         if (reset($stk) == SERVICES_JSON_IN_ARR) {
    646                             return $arr;
    647 
    648                         } else {
    649                             return $obj;
    650 
    651                         }
    652                     }
    653 
    654                     //print("\nparsing {$chrs}\n");
    655 
    656                     $strlen_chrs = strlen($chrs);
    657 
    658                     for ($c = 0; $c <= $strlen_chrs; ++$c) {
    659 
    660                         $top = end($stk);
    661                         $substr_chrs_c_2 = substr($chrs, $c, 2);
    662 
    663                         if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
    664                             // found a comma that is not inside a string, array, etc.,
    665                             // OR we've reached the end of the character list
    666                             $slice = substr($chrs, $top['where'], ($c - $top['where']));
    667                             array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
    668                             //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
    669 
    670                             if (reset($stk) == SERVICES_JSON_IN_ARR) {
    671                                 // we are in an array, so just push an element onto the stack
    672                                 array_push($arr, $this->decode($slice));
    673 
    674                             } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
    675                                 // we are in an object, so figure
    676                                 // out the property name and set an
    677                                 // element in an associative array,
    678                                 // for now
    679                                 $parts = array();
    680                                
    681                                 if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
    682                                     // "name":value pair
    683                                     $key = $this->decode($parts[1]);
    684                                     $val = $this->decode($parts[2]);
    685 
    686                                     if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
    687                                         $obj[$key] = $val;
    688                                     } else {
    689                                         $obj->$key = $val;
    690                                     }
    691                                 } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
    692                                     // name:value pair, where name is unquoted
    693                                     $key = $parts[1];
    694                                     $val = $this->decode($parts[2]);
    695 
    696                                     if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
    697                                         $obj[$key] = $val;
    698                                     } else {
    699                                         $obj->$key = $val;
    700                                     }
    701                                 }
    702 
    703                             }
    704 
    705                         } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
    706                             // found a quote, and we are not inside a string
    707                             array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
    708                             //print("Found start of string at {$c}\n");
    709 
    710                         } elseif (($chrs{$c} == $top['delim']) &&
    711                                  ($top['what'] == SERVICES_JSON_IN_STR) &&
    712                                  ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
    713                             // found a quote, we're in a string, and it's not escaped
    714                             // we know that it's not escaped becase there is _not_ an
    715                             // odd number of backslashes at the end of the string so far
    716                             array_pop($stk);
    717                             //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
    718 
    719                         } elseif (($chrs{$c} == '[') &&
    720                                  in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
    721                             // found a left-bracket, and we are in an array, object, or slice
    722                             array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
    723                             //print("Found start of array at {$c}\n");
    724 
    725                         } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
    726                             // found a right-bracket, and we're in an array
    727                             array_pop($stk);
    728                             //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
    729 
    730                         } elseif (($chrs{$c} == '{') &&
    731                                  in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
    732                             // found a left-brace, and we are in an array, object, or slice
    733                             array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
    734                             //print("Found start of object at {$c}\n");
    735 
    736                         } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
    737                             // found a right-brace, and we're in an object
    738                             array_pop($stk);
    739                             //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
    740 
    741                         } elseif (($substr_chrs_c_2 == '/*') &&
    742                                  in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
    743                             // found a comment start, and we are in an array, object, or slice
    744                             array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
    745                             $c++;
    746                             //print("Found start of comment at {$c}\n");
    747 
    748                         } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
    749                             // found a comment end, and we're in one now
    750                             array_pop($stk);
    751                             $c++;
    752 
    753                             for ($i = $top['where']; $i <= $c; ++$i)
    754                                 $chrs = substr_replace($chrs, ' ', $i, 1);
    755 
    756                             //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
    757 
    758                         }
    759 
    760                     }
    761 
    762                     if (reset($stk) == SERVICES_JSON_IN_ARR) {
    763                         return $arr;
    764 
    765                     } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
    766                         return $obj;
    767 
    768                     }
    769 
    770                 }
    771         }
    772     }
    773 
    774     /**
    775      * @todo Ultimately, this should just call PEAR::isError()
    776      */
    777     function isError($data, $code = null)
    778     {
    779         if (class_exists('pear')) {
    780             return PEAR::isError($data, $code);
    781         } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
    782                                  is_subclass_of($data, 'services_json_error'))) {
    783             return true;
    784         }
    785 
    786         return false;
    787     }
     128class Services_JSON {
     129        /**
     130         * constructs a new JSON instance
     131         *
     132         * @param    int $use object behavior flags; combine with boolean-OR
     133         *
     134         *                           possible values:
     135         *                           - SERVICES_JSON_LOOSE_TYPE:  loose typing.
     136         *                                   "{...}" syntax creates associative arrays
     137         *                                   instead of objects in decode().
     138         *                           - SERVICES_JSON_SUPPRESS_ERRORS:  error suppression.
     139         *                                   Values which can't be encoded (e.g. resources)
     140         *                                   appear as NULL instead of throwing errors.
     141         *                                   By default, a deeply-nested resource will
     142         *                                   bubble up with an error, so all return values
     143         *                                   from encode() should be checked with isError()
     144         */
     145        function Services_JSON($use = 0) {
     146                $this->use = $use;
     147        }
     148
     149        /**
     150         * convert a string from one UTF-16 char to one UTF-8 char
     151         *
     152         * Normally should be handled by mb_convert_encoding, but
     153         * provides a slower PHP-only method for installations
     154         * that lack the multibye string extension.
     155         *
     156         * @param    string $utf16 UTF-16 character
     157         *
     158         * @return   string  UTF-8 character
     159         * @access   private
     160         */
     161        function utf162utf8($utf16) {
     162                // oh please oh please oh please oh please oh please
     163                if (function_exists('mb_convert_encoding')) {
     164                        return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
     165                }
     166
     167                $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
     168
     169                switch (true) {
     170                        case ((0x7F & $bytes) == $bytes):
     171                                // this case should never be reached, because we are in ASCII range
     172                                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     173                                return chr(0x7F & $bytes);
     174
     175                        case (0x07FF & $bytes) == $bytes:
     176                                // return a 2-byte UTF-8 character
     177                                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     178                                return chr(0xC0 | (($bytes >> 6) & 0x1F))
     179                                        . chr(0x80 | ($bytes & 0x3F));
     180
     181                        case (0xFFFF & $bytes) == $bytes:
     182                                // return a 3-byte UTF-8 character
     183                                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     184                                return chr(0xE0 | (($bytes >> 12) & 0x0F))
     185                                        . chr(0x80 | (($bytes >> 6) & 0x3F))
     186                                        . chr(0x80 | ($bytes & 0x3F));
     187                }
     188
     189                // ignoring UTF-32 for now, sorry
     190                return '';
     191        }
     192
     193        /**
     194         * convert a string from one UTF-8 char to one UTF-16 char
     195         *
     196         * Normally should be handled by mb_convert_encoding, but
     197         * provides a slower PHP-only method for installations
     198         * that lack the multibye string extension.
     199         *
     200         * @param    string $utf8 UTF-8 character
     201         *
     202         * @return   string  UTF-16 character
     203         * @access   private
     204         */
     205        function utf82utf16($utf8) {
     206                // oh please oh please oh please oh please oh please
     207                if (function_exists('mb_convert_encoding')) {
     208                        return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
     209                }
     210
     211                switch (strlen($utf8)) {
     212                        case 1:
     213                                // this case should never be reached, because we are in ASCII range
     214                                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     215                                return $utf8;
     216
     217                        case 2:
     218                                // return a UTF-16 character from a 2-byte UTF-8 char
     219                                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     220                                return chr(0x07 & (ord($utf8{0}) >> 2))
     221                                        . chr((0xC0 & (ord($utf8{0}) << 6))
     222                                                | (0x3F & ord($utf8{1})));
     223
     224                        case 3:
     225                                // return a UTF-16 character from a 3-byte UTF-8 char
     226                                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     227                                return chr((0xF0 & (ord($utf8{0}) << 4))
     228                                                | (0x0F & (ord($utf8{1}) >> 2)))
     229                                        . chr((0xC0 & (ord($utf8{1}) << 6))
     230                                                | (0x7F & ord($utf8{2})));
     231                }
     232
     233                // ignoring UTF-32 for now, sorry
     234                return '';
     235        }
     236
     237        /**
     238         * encodes an arbitrary variable into JSON format
     239         *
     240         * @param    mixed $var any number, boolean, string, array, or object to be encoded.
     241         *                           see argument 1 to Services_JSON() above for array-parsing behavior.
     242         *                           if var is a strng, note that encode() always expects it
     243         *                           to be in ASCII or UTF-8 format!
     244         *
     245         * @return   mixed   JSON string representation of input var or an error if a problem occurs
     246         * @access   public
     247         */
     248        function encode($var) {
     249                switch (gettype($var)) {
     250                        case 'boolean':
     251                                return $var ? 'true' : 'false';
     252
     253                        case 'NULL':
     254                                return 'null';
     255
     256                        case 'integer':
     257                                return (int) $var;
     258
     259                        case 'double':
     260                        case 'float':
     261                                return (float) $var;
     262
     263                        case 'string':
     264                                // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
     265                                $ascii = '';
     266                                $strlen_var = strlen($var);
     267
     268                                /*
     269                                 * Iterate over every character in the string,
     270                                 * escaping with a slash or encoding to UTF-8 where necessary
     271                                 */
     272                                for ($c = 0; $c < $strlen_var; ++$c) {
     273
     274                                        $ord_var_c = ord($var{$c});
     275
     276                                        switch (true) {
     277                                                case $ord_var_c == 0x08:
     278                                                        $ascii .= '\b';
     279                                                        break;
     280                                                case $ord_var_c == 0x09:
     281                                                        $ascii .= '\t';
     282                                                        break;
     283                                                case $ord_var_c == 0x0A:
     284                                                        $ascii .= '\n';
     285                                                        break;
     286                                                case $ord_var_c == 0x0C:
     287                                                        $ascii .= '\f';
     288                                                        break;
     289                                                case $ord_var_c == 0x0D:
     290                                                        $ascii .= '\r';
     291                                                        break;
     292
     293                                                case $ord_var_c == 0x22:
     294                                                case $ord_var_c == 0x2F:
     295                                                case $ord_var_c == 0x5C:
     296                                                        // double quote, slash, slosh
     297                                                        $ascii .= '\\' . $var{$c};
     298                                                        break;
     299
     300                                                case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
     301                                                        // characters U-00000000 - U-0000007F (same as ASCII)
     302                                                        $ascii .= $var{$c};
     303                                                        break;
     304
     305                                                case (($ord_var_c & 0xE0) == 0xC0):
     306                                                        // characters U-00000080 - U-000007FF, mask 110XXXXX
     307                                                        // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     308                                                        $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
     309                                                        $c += 1;
     310                                                        $utf16 = $this->utf82utf16($char);
     311                                                        $ascii .= sprintf('\u%04s', bin2hex($utf16));
     312                                                        break;
     313
     314                                                case (($ord_var_c & 0xF0) == 0xE0):
     315                                                        // characters U-00000800 - U-0000FFFF, mask 1110XXXX
     316                                                        // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     317                                                        $char = pack('C*', $ord_var_c,
     318                                                                ord($var{$c + 1}),
     319                                                                ord($var{$c + 2}));
     320                                                        $c += 2;
     321                                                        $utf16 = $this->utf82utf16($char);
     322                                                        $ascii .= sprintf('\u%04s', bin2hex($utf16));
     323                                                        break;
     324
     325                                                case (($ord_var_c & 0xF8) == 0xF0):
     326                                                        // characters U-00010000 - U-001FFFFF, mask 11110XXX
     327                                                        // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     328                                                        $char = pack('C*', $ord_var_c,
     329                                                                ord($var{$c + 1}),
     330                                                                ord($var{$c + 2}),
     331                                                                ord($var{$c + 3}));
     332                                                        $c += 3;
     333                                                        $utf16 = $this->utf82utf16($char);
     334                                                        $ascii .= sprintf('\u%04s', bin2hex($utf16));
     335                                                        break;
     336
     337                                                case (($ord_var_c & 0xFC) == 0xF8):
     338                                                        // characters U-00200000 - U-03FFFFFF, mask 111110XX
     339                                                        // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     340                                                        $char = pack('C*', $ord_var_c,
     341                                                                ord($var{$c + 1}),
     342                                                                ord($var{$c + 2}),
     343                                                                ord($var{$c + 3}),
     344                                                                ord($var{$c + 4}));
     345                                                        $c += 4;
     346                                                        $utf16 = $this->utf82utf16($char);
     347                                                        $ascii .= sprintf('\u%04s', bin2hex($utf16));
     348                                                        break;
     349
     350                                                case (($ord_var_c & 0xFE) == 0xFC):
     351                                                        // characters U-04000000 - U-7FFFFFFF, mask 1111110X
     352                                                        // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     353                                                        $char = pack('C*', $ord_var_c,
     354                                                                ord($var{$c + 1}),
     355                                                                ord($var{$c + 2}),
     356                                                                ord($var{$c + 3}),
     357                                                                ord($var{$c + 4}),
     358                                                                ord($var{$c + 5}));
     359                                                        $c += 5;
     360                                                        $utf16 = $this->utf82utf16($char);
     361                                                        $ascii .= sprintf('\u%04s', bin2hex($utf16));
     362                                                        break;
     363                                        }
     364                                }
     365
     366                                return '"' . $ascii . '"';
     367
     368                        case 'array':
     369                                /*
     370                                 * As per JSON spec if any array key is not an integer
     371                                 * we must treat the the whole array as an object. We
     372                                 * also try to catch a sparsely populated associative
     373                                 * array with numeric keys here because some JS engines
     374                                 * will create an array with empty indexes up to
     375                                 * max_index which can cause memory issues and because
     376                                 * the keys, which may be relevant, will be remapped
     377                                 * otherwise.
     378                                 *
     379                                 * As per the ECMA and JSON specification an object may
     380                                 * have any string as a property. Unfortunately due to
     381                                 * a hole in the ECMA specification if the key is a
     382                                 * ECMA reserved word or starts with a digit the
     383                                 * parameter is only accessible using ECMAScript's
     384                                 * bracket notation.
     385                                 */
     386
     387                                // treat as a JSON object
     388                                if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
     389                                        $properties = array_map(array($this, 'name_value'),
     390                                                array_keys($var),
     391                                                array_values($var));
     392
     393                                        foreach ($properties as $property) {
     394                                                if (Services_JSON::isError($property)) {
     395                                                        return $property;
     396                                                }
     397                                        }
     398
     399                                        return '{' . join(',', $properties) . '}';
     400                                }
     401
     402                                // treat it like a regular array
     403                                $elements = array_map(array($this, 'encode'), $var);
     404
     405                                foreach ($elements as $element) {
     406                                        if (Services_JSON::isError($element)) {
     407                                                return $element;
     408                                        }
     409                                }
     410
     411                                return '[' . join(',', $elements) . ']';
     412
     413                        case 'object':
     414                                $vars = get_object_vars($var);
     415
     416                                $properties = array_map(array($this, 'name_value'),
     417                                        array_keys($vars),
     418                                        array_values($vars));
     419
     420                                foreach ($properties as $property) {
     421                                        if (Services_JSON::isError($property)) {
     422                                                return $property;
     423                                        }
     424                                }
     425
     426                                return '{' . join(',', $properties) . '}';
     427
     428                        default:
     429                                return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
     430                                        ? 'null'
     431                                        : new Services_JSON_Error(gettype($var) . " can not be encoded as JSON string");
     432                }
     433        }
     434
     435        /**
     436         * array-walking function for use in generating JSON-formatted name-value pairs
     437         *
     438         * @param    string $name name of key to use
     439         * @param    mixed $value reference to an array element to be encoded
     440         *
     441         * @return   string  JSON-formatted name-value pair, like '"name":value'
     442         * @access   private
     443         */
     444        function name_value($name, $value) {
     445                $encoded_value = $this->encode($value);
     446
     447                if (Services_JSON::isError($encoded_value)) {
     448                        return $encoded_value;
     449                }
     450
     451                return $this->encode(strval($name)) . ':' . $encoded_value;
     452        }
     453
     454        /**
     455         * reduce a string by removing leading and trailing comments and whitespace
     456         *
     457         * @param    $str    string      string value to strip of comments and whitespace
     458         *
     459         * @return   string  string value stripped of comments and whitespace
     460         * @access   private
     461         */
     462        function reduce_string($str) {
     463                $str = preg_replace(array(
     464
     465                        // eliminate single line comments in '// ...' form
     466                        '#^\s*//(.+)$#m',
     467
     468                        // eliminate multi-line comments in '/* ... */' form, at start of string
     469                        '#^\s*/\*(.+)\*/#Us',
     470
     471                        // eliminate multi-line comments in '/* ... */' form, at end of string
     472                        '#/\*(.+)\*/\s*$#Us',
     473
     474                ), '', $str);
     475
     476                // eliminate extraneous space
     477                return trim($str);
     478        }
     479
     480        /**
     481         * decodes a JSON string into appropriate variable
     482         *
     483         * @param    string $str JSON-formatted string
     484         *
     485         * @return   mixed   number, boolean, string, array, or object
     486         *                   corresponding to given JSON input string.
     487         *                   See argument 1 to Services_JSON() above for object-output behavior.
     488         *                   Note that decode() always returns strings
     489         *                   in ASCII or UTF-8 format!
     490         * @access   public
     491         */
     492        function decode($str) {
     493                $str = $this->reduce_string($str);
     494
     495                switch (strtolower($str)) {
     496                        case 'true':
     497                                return true;
     498
     499                        case 'false':
     500                                return false;
     501
     502                        case 'null':
     503                                return null;
     504
     505                        default:
     506                                $m = array();
     507
     508                                if (is_numeric($str)) {
     509                                        // Lookie-loo, it's a number
     510
     511                                        // This would work on its own, but I'm trying to be
     512                                        // good about returning integers where appropriate:
     513                                        // return (float)$str;
     514
     515                                        // Return float or int, as appropriate
     516                                        return ((float) $str == (integer) $str)
     517                                                ? (integer) $str
     518                                                : (float) $str;
     519
     520                                } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
     521                                        // STRINGS RETURNED IN UTF-8 FORMAT
     522                                        $delim = substr($str, 0, 1);
     523                                        $chrs = substr($str, 1, -1);
     524                                        $utf8 = '';
     525                                        $strlen_chrs = strlen($chrs);
     526
     527                                        for ($c = 0; $c < $strlen_chrs; ++$c) {