Advertisement
HJin_me

twip t.co expand patch

Oct 18th, 2011
658
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 14.05 KB | None | 0 0
  1. <?php
  2. require('include/twitteroauth.php');
  3. require('image_proxy.php');
  4. class twip{
  5.     const PARENT_API = 'https://api.twitter.com/';
  6.     const PARENT_SEARCH_API = 'http://search.twitter.com/';
  7.     const ERR_LOGFILE = 'err.txt';
  8.     const LOGFILE = 'log.txt';
  9.     const LOGTIMEZONE = 'Etc/GMT-8';
  10.     const BASE_URL = 'http://yegle.net/twip/';
  11.     const API_VERSION = '1';
  12.  
  13.     public function twip($options = null){
  14.         $this->parse_variables($options);
  15.  
  16.         ob_start();
  17.         $compressed = $this->compress && Extension_Loaded('zlib') && ob_start("ob_gzhandler");
  18.        
  19.         if($this->mode=='t'){
  20.             $this->transparent_mode();
  21.         }
  22.         else if($this->mode=='o'){
  23.             $this->override_mode();
  24.         }
  25.         else if($this->mode=='i'){
  26.             $this->override_mode(true);
  27.         }
  28.         else{
  29.             header('HTTP/1.0 400 Bad Request');
  30.         }
  31.  
  32.         $str = ob_get_contents();
  33.         if ($compressed) ob_end_flush();
  34.         header('Content-Length: '.ob_get_length());
  35.         ob_flush();
  36.  
  37.         if($this->debug){
  38.             print_r($this);
  39.             print_r($_SERVER);
  40.             file_put_contents('debug',ob_get_contents().$str);
  41.             ob_clean();
  42.         }
  43.         if($this->dolog){
  44.             file_put_contents('log',$this->method.' '.$this->request_uri."\n",FILE_APPEND);
  45.         }
  46.     }
  47.    
  48.     private function expand_tco(&$data, $type) {
  49.         if("json" === $type){
  50.             if(!isset($data->entities)){
  51.                 return;
  52.             }
  53.             foreach($data->entities->urls as &$url) {
  54.                 $data->text = str_replace($url->url, $url->expanded_url, $data->text);
  55.                 $url->url = $url->expanded_url;
  56.             }
  57.             foreach($data->entities->urls as &$url) {
  58.                 $tcoPos = mb_strpos($data->text, $url->expanded_url);
  59.                 $url->indices[0] = $tcoPos;
  60.                 $url->indices[1] = $url->indices[0] + mb_strlen($url->expanded_url);
  61.             }
  62.             foreach($data->entities->media as &$media) {
  63.                 $data->text = str_replace($media->url, $media->media_url, $data->text);
  64.                 $media->url = $media->media_url;
  65.             }
  66.             foreach($data->entities->media as &$media) {
  67.                 $tcoPos = mb_strpos($data->text, $media->media_url);
  68.                 $media->indices[0] = $tcoPos;
  69.                 $media->indices[1] = $media->indices[0] + mb_strlen($media->media_url);
  70.             }
  71.         } else {
  72.             //遍历 entities
  73.             $texts = $data->parentNode->getElementsByTagName('text');
  74.             foreach($texts as $v) {
  75.                 if($v->parentNode->nodeName == $data->parentNode->nodeName) {
  76.                     $text = $v;
  77.                 }
  78.             }
  79.             $urls = $data->getElementsByTagName('urls')->item(0);
  80.             if($urls->hasChildNodes()) {
  81.                 foreach($urls->childNodes as $url) {
  82.                     if($url->nodeName == 'url' && ($expanded_url = $url->getElementsByTagName('expanded_url')->item(0)->nodeValue) != '') {
  83.                         //替换 t.co 地址
  84.                         $tcoUrl = $url->getElementsByTagName('url')->item(0)->nodeValue;
  85.                         //替换 tweet 内容中的 t.co
  86.                         $text->nodeValue = htmlspecialchars(str_replace($tcoUrl, $expanded_url, $text->nodeValue));
  87.                         $url->getElementsByTagName('url')->item(0)->nodeValue = htmlspecialchars($expanded_url);
  88.                     }
  89.                 }
  90.                 foreach($urls->childNodes as $url) {
  91.                     if($url->nodeName == 'url' && ($expanded_url = $url->getElementsByTagName('expanded_url')->item(0)->nodeValue) != '') {
  92.                         //修改 url 的截取参数
  93.                         //$expanded_url = $url->getElementsByTagName('expanded_url')->item(0)->textContent;
  94.                         $tcoPos = mb_strpos($text->textContent, $expanded_url);
  95.                         $url->setAttribute("start", $tcoPos);
  96.                         $url->setAttribute("end", $tcoPos + mb_strlen($expanded_url));
  97.                     }
  98.                 }
  99.             }
  100.  
  101.             $media = $data->getElementsByTagName('media');
  102.             if($media->length > 0 && $media->item(0)->hasChildNodes()) {
  103.                 foreach($media->item(0)->childNodes as $creative) {
  104.                     if($creative->nodeName == 'creative' && $creative->getElementsByTagName('media_url')->length >0 && ($media_url = $creative->getElementsByTagName('media_url')->item(0)->nodeValue) != '') {
  105.                         //替换 t.co 地址
  106.                         $tcoUrl = $creative->getElementsByTagName('url')->item(0)->nodeValue;
  107.                         //替换 tweet 内容中的 t.co
  108.                         $text->nodeValue = htmlspecialchars(str_replace($tcoUrl, $media_url, $text->nodeValue));
  109.                         $creative->getElementsByTagName('url')->item(0)->nodeValue = htmlspecialchars($media_url);
  110.                     }
  111.                 }
  112.                 foreach($media->item(0)->childNodes as $creative) {
  113.                     if($creative->nodeName == 'creative' && $creative->getElementsByTagName('media_url')->length >0 && ($media_url = $creative->getElementsByTagName('media_url')->item(0)->nodeValue) != '') {
  114.                         //修改 url 的截取参数
  115.                         $tcoPos = mb_strpos($text->textContent, $media_url);
  116.                         $creative->setAttribute("start", $tcoPos);
  117.                         $creative->setAttribute("end", $tcoPos + mb_strlen($media_url));
  118.                     }
  119.                 }
  120.             }
  121.         }
  122.     }
  123.    
  124.     private function parse_entities($data) {
  125.         mb_internal_encoding("UTF-8");
  126.         if(strpos($this->request_uri, ".json") > 0) {
  127.             //json
  128.             $json = json_decode($data);
  129.             //32bit int / snowflake patch
  130.             if (is_array($json)) {
  131.                 foreach($json as $key => $status) {
  132.                     if($status->id_str) {
  133.                         $json[$key]->id = $status->id_str;
  134.                     }
  135.                     if($status->in_reply_to_status_id_str) {
  136.                         $json[$key]->in_reply_to_status_id = $status->in_reply_to_status_id_str;
  137.                     }
  138.                     if($status->retweeted_status->id_str) {
  139.                         $json[$key]->retweeted_status->id = $status->retweeted_status->id_str;
  140.                     }
  141.                 }
  142.             }
  143.             foreach ($json as &$status) {
  144.                 $this->expand_tco($status, "json");
  145.                 if(isset($status->retweeted_status)) {
  146.                     $this->expand_tco($status->retweeted_status, "json");
  147.                 }
  148.             }
  149.             $data = preg_replace("/\"(in_reply_to_status_id|id)\"\:\"(\d{12,})\",/", "\"$1\":$2,", json_encode($json));
  150.             return $data;
  151.         } else {
  152.             //xml
  153.             $xml = new DomDocument();
  154.             if (false !== $xml->loadXML($data)) {
  155.                 $arr_entities = $xml->getElementsByTagName('entities');
  156.                 foreach ($arr_entities as $entities) {
  157.                     //遍历每条tweets
  158.                     $this->expand_tco($entities, "xml");
  159.                 }
  160.                 return $xml->saveXML();
  161.             } else {
  162.                 return $data;
  163.             }
  164.         }
  165.     }
  166.  
  167.     private function echo_token(){
  168.             $str = 'oauth_token='.$this->access_token['oauth_token']."&oauth_token_secret=".$this->access_token['oauth_token_secret']."&user_id=".$this->access_token['user_id']."&screen_name=".$this->access_token['screen_name'].'&x_auth_expires=0'."\n";
  169.             echo $str;
  170.     }
  171.  
  172.     private function parse_variables($options){
  173.         //parse options
  174.         $this->parent_api = isset($options['parent_api']) ? $options['parent_api'] : self::PARENT_API;
  175.         $this->parent_search_api = isset($options['parent_search_api']) ? $options['parent_search_api'] : self::PARENT_SEARCH_API;
  176.         $this->api_version = isset($options['api_version']) ? $options['api_version'] : self::API_VERSION;
  177.         $this->debug = isset($options['debug']) ? !!$options['debug'] : FALSE;
  178.         $this->dolog = isset($options['dolog']) ? !!$options['dolog'] : FALSE;
  179.         $this->compress = isset($options['compress']) ? !!$options['compress'] : FALSE;
  180.         $this->oauth_key = $options['oauth_key'];
  181.         $this->oauth_secret = $options['oauth_secret'];
  182.  
  183.         if(substr($this->parent_api, -1) !== '/') $this->parent_api .= '/';
  184.         if(substr($this->parent_search_api, -1) !== '/') $this->parent_search_api .= '/';
  185.  
  186.         $this->base_url = isset($options['base_url']) ? trim($options['base_url'],'/').'/' : self::BASE_URL;
  187.         if(preg_match('/^https?:\/\//i',$this->base_url) == 0){
  188.             $this->base_url = 'http://'.$this->base_url;
  189.         }
  190.  
  191.         //parse $_SERVER
  192.         $this->method = $_SERVER['REQUEST_METHOD'];
  193.  
  194.  
  195.         $this->parse_request_uri();
  196.     }
  197.  
  198.     private function override_mode($imageproxy = FALSE){
  199.         $tokenfile = glob('oauth/'.$this->password.'.*');
  200.         if(!empty($tokenfile)){
  201.             $access_token = @file_get_contents($tokenfile[0]);
  202.         }
  203.         if(empty($access_token)){
  204.             header('HTTP/1.1 401 Unauthorized');
  205.             header('WWW-Authenticate: Basic realm="Twip4 Override Mode"');
  206.             echo 'You are not allowed to use this API proxy';
  207.             exit();
  208.         }
  209.         $access_token = unserialize($access_token);
  210.         $this->access_token = $access_token;
  211.  
  212.         if(preg_match('!oauth/access_token\??!', $this->request_uri)){
  213.             $this->echo_token();
  214.             return;
  215.         }
  216.  
  217.         if($imageproxy){
  218.             if($this->method=='POST'){
  219.                 echo imageUpload($this->oauth_key, $this->oauth_secret, $this->access_token);
  220.             }else{
  221.                 echo 'The image proxy needs POST method.';
  222.             }
  223.             return;
  224.         }
  225.  
  226.         if($this->request_uri == null){
  227.             echo 'click <a href="'.$this->base_url.'oauth.php">HERE</a> to get your API url';
  228.             return;
  229.         }
  230.         $this->parameters = $this->get_parameters();
  231.         $this->uri_fixer();
  232.         $this->connection = new TwitterOAuth($this->oauth_key, $this->oauth_secret, $this->access_token['oauth_token'], $this->access_token['oauth_token_secret']);
  233.         switch($this->method){
  234.             case 'POST':
  235.                 echo $this->connection->post($this->request_uri,$this->parameters);
  236.                 break;
  237.             case 'DELETE':
  238.                 echo $this->connection->delete($this->request_uri,$this->parameters);
  239.                 break;
  240.             default:
  241.                 //edit by Huang Jin for replace t.co
  242.                 //echo $this->connection->get($this->request_uri);
  243.                 //edit start
  244.                 echo $this->parse_entities( $this->connection->get($this->request_uri . "&include_entities=true"));
  245.                 //edit end
  246.                 break;
  247.         }
  248.     }
  249.  
  250.     private function transparent_mode(){
  251.         $this->uri_fixer();
  252.         $ch = curl_init($this->request_uri);
  253.         $this->request_headers = OAuthUtil::get_headers();
  254.         if($this->api_type == 'search'){
  255.             $this->request_headers['Host'] = 'search.twitter.com';
  256.         }
  257.         else{
  258.             $this->request_headers['Host'] = 'api.twitter.com';
  259.         }
  260.         if(isset($this->request_headers['Content-Type']) &&
  261.                 $this->request_headers['Content-Type'] == 'application/x-www-form-urlencoded' ){
  262.             $this->parameters = $this->get_parameters(false);
  263.         }else{
  264.             $this->parameters = $this->get_parameters(true);
  265.         }
  266.         $forwarded_headers = array(
  267.             'Host',
  268.             'User-Agent',
  269.             'Authorization',
  270.             'Content-Type',
  271.             'X-Forwarded-For',
  272.             'Expect',
  273.             );
  274.         foreach($forwarded_headers as $header){
  275.             if(isset($this->request_headers[$header])){
  276.                 $this->forwarded_headers[] = $header.': '.$this->request_headers[$header];
  277.             }
  278.         }
  279.         if(!isset($this->forwarded_headers['Expect'])) $this->forwarded_headers[] = 'Expect:';
  280.         curl_setopt($ch,CURLOPT_HTTPHEADER,$this->forwarded_headers);
  281.         curl_setopt($ch,CURLOPT_HEADERFUNCTION,array($this,'headerfunction'));
  282.         if($this->method != 'GET'){
  283.             curl_setopt($ch,CURLOPT_CUSTOMREQUEST,$this->method);
  284.             curl_setopt($ch,CURLOPT_POSTFIELDS,$this->parameters);
  285.         }
  286.         curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
  287.         $ret = curl_exec($ch);
  288.         //fixme:redirect request back to twip,this is nasty and insecure...
  289.         if(strpos($this->request_uri,'oauth/authorize?oauth_token=')!==NULL){
  290.             $ret = str_replace('<form action="https://api.twitter.com/oauth/authorize"','<form action="'.$this->base_url.'t/oauth/authorize"',$ret);
  291.             $ret = str_replace('<div id="signin_form">','<h1><strong style="color:red">Warning!This page is proxied by twip and therefore you may leak your password to API proxy owner!</strong></h1><div id="signin_form">',$ret);
  292.         }
  293.         echo $ret;
  294.     }
  295.  
  296.     private function uri_fixer(){
  297.         if( isset($_SERVER['HTTP_USER_AGENT']) && substr($_SERVER['HTTP_USER_AGENT'],0,6) == 'twhirl' ){
  298.             $this->request_uri = str_replace('api/','',$this->request_uri);//remove "api/"
  299.         }
  300.         if(isset($this->api_type) && $this->api_type == 'search'){
  301.             $this->request_uri = $this->parent_search_api.$this->request_uri;
  302.         }
  303.         else{
  304.             if(strpos($this->request_uri,'oauth/') === 0 || preg_match('/^[0-9]\/(.*)/',$this->request_uri)){
  305.                 $this->request_uri = $this->parent_api.$this->request_uri;
  306.             }else{
  307.                 $this->request_uri = $this->parent_api.$this->api_version.'/'.$this->request_uri;
  308.             }
  309.         }
  310.     }
  311.  
  312.     private function parse_request_uri(){
  313.         $full_request_uri = substr($_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'],strlen(preg_replace('/^https?:\/\//i','',$this->base_url)));
  314.         if(strpos($full_request_uri,'o/')===0){
  315.             list($this->mode,$this->password,$this->request_uri) = explode('/',$full_request_uri,3);
  316.             $this->mode = 'o';
  317.         }
  318.         elseif(strpos($full_request_uri,'t/')===0){
  319.             list($this->mode,$this->request_uri) = explode('/',$full_request_uri,2);
  320.             $this->mode = 't';
  321.         }
  322.         elseif(strpos($full_request_uri,'i/')===0){
  323.             list($this->mode,$this->password,$this->request_uri) = explode('/',$full_request_uri,3);
  324.             $this->mode = 'i';
  325.         }
  326.         $this->request_uri = preg_replace('/\/+/','/',$this->request_uri);
  327.         if((strpos($this->request_uri,'search.') === 0)){
  328.             $this->api_type = 'search';
  329.         }
  330.     }
  331.  
  332.     private function headerfunction($ch,$str){
  333.         if(strpos($str,'Content-Length:')!==NULL){
  334.             header($str);
  335.         }
  336.         $this->response_headers[] = $str;
  337.         return strlen($str);
  338.     }
  339.  
  340.     private function get_parameters($returnArray = TRUE){
  341.         $data = file_get_contents('php://input');
  342.         if(!$returnArray) return $data;
  343.         $ret = array();
  344.         parse_str($data,$ret);
  345.         return $ret;
  346.     }
  347. }
  348. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement