Trackback.php

Go to the documentation of this file.
00001 <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
00002 /**
00003  * CodeIgniter
00004  *
00005  * An open source application development framework for PHP 4.3.2 or newer
00006  *
00007  * @package             CodeIgniter
00008  * @author              ExpressionEngine Dev Team
00009  * @copyright   Copyright (c) 2006, EllisLab, Inc.
00010  * @license             http://codeigniter.com/user_guide/license.html
00011  * @link                http://codeigniter.com
00012  * @since               Version 1.0
00013  * @filesource
00014  */
00015 
00016 // ------------------------------------------------------------------------
00017 
00018 /**
00019  * Trackback Class
00020  *
00021  * Trackback Sending/Receiving Class
00022  *
00023  * @package             CodeIgniter
00024  * @subpackage  Libraries
00025  * @category    Trackbacks
00026  * @author              ExpressionEngine Dev Team
00027  * @link                http://codeigniter.com/user_guide/libraries/trackback.html
00028  */
00029 class CI_Trackback {
00030                 
00031         var $time_format        = 'local';
00032         var $charset            = 'UTF-8';
00033         var $data                       = array('url' => '', 'title' => '', 'excerpt' => '', 'blog_name' => '', 'charset' => '');
00034         var $convert_ascii      = TRUE;
00035         var $response           = '';
00036         var $error_msg          = array();
00037 
00038         /**
00039          * Constructor
00040          *
00041          * @access      public
00042          */
00043         function CI_Trackback()
00044         {
00045                 log_message('debug', "Trackback Class Initialized");
00046         }
00047         
00048         // --------------------------------------------------------------------
00049         
00050         /**
00051          * Send Trackback
00052          *
00053          * @access      public
00054          * @param       array
00055          * @return      bool
00056          */     
00057         function send($tb_data)
00058         {               
00059                 if ( ! is_array($tb_data))
00060                 {
00061                         $this->set_error('The send() method must be passed an array');
00062                         return FALSE;
00063                 }
00064                 
00065                 // Pre-process the Trackback Data
00066                 foreach (array('url', 'title', 'excerpt', 'blog_name', 'ping_url') as $item)
00067                 {
00068                         if ( ! isset($tb_data[$item]))
00069                         {
00070                                 $this->set_error('Required item missing: '.$item);
00071                                 return FALSE;
00072                         }
00073                         
00074                         switch ($item)
00075                         {
00076                                 case 'ping_url' : $$item = $this->extract_urls($tb_data[$item]);
00077                                         break;
00078                                 case 'excerpt'  : $$item = $this->limit_characters($this->convert_xml(strip_tags(stripslashes($tb_data[$item]))));
00079                                         break;
00080                                 case 'url'              : $$item = str_replace('&#45;', '-', $this->convert_xml(strip_tags(stripslashes($tb_data[$item]))));
00081                                         break;
00082                                 default                 : $$item = $this->convert_xml(strip_tags(stripslashes($tb_data[$item])));
00083                                         break;
00084                         }
00085 
00086                         // Convert High ASCII Characters
00087                         if ($this->convert_ascii == TRUE)
00088                         {
00089                                 if ($item == 'excerpt')
00090                                 {
00091                                         $$item = $this->convert_ascii($$item);
00092                                 }
00093                                 elseif ($item == 'title')
00094                                 {
00095                                         $$item = $this->convert_ascii($$item);
00096                                 }
00097                                 elseif($item == 'blog_name')
00098                                 {
00099                                         $$item = $this->convert_ascii($$item);
00100                                 }
00101                         }
00102                 }
00103 
00104                 // Build the Trackback data string
00105                 $charset = ( ! isset($tb_data['charset'])) ? $this->charset : $tb_data['charset'];
00106                 
00107                 $data = "url=".rawurlencode($url)."&title=".rawurlencode($title)."&blog_name=".rawurlencode($blog_name)."&excerpt=".rawurlencode($excerpt)."&charset=".rawurlencode($charset);
00108                                 
00109                 // Send Trackback(s)
00110                 $return = TRUE;
00111                 if (count($ping_url) > 0)
00112                 {
00113                         foreach ($ping_url as $url)
00114                         {
00115                                 if ($this->process($url, $data) == FALSE)
00116                                 {
00117                                         $return = FALSE;
00118                                 }
00119                         }       
00120                 }
00121 
00122                 return $return;
00123         }
00124         
00125         // --------------------------------------------------------------------
00126         
00127         /**
00128          * Receive Trackback  Data
00129          *
00130          * This function simply validates the incoming TB data.
00131          * It returns false on failure and true on success.
00132          * If the data is valid it is set to the $this->data array
00133          * so that it can be inserted into a database.
00134          *
00135          * @access      public
00136          * @return      bool
00137          */     
00138         function receive()
00139         {                                       
00140                 foreach (array('url', 'title', 'blog_name', 'excerpt') as $val)
00141                 {
00142                         if ( ! isset($_POST[$val]) OR $_POST[$val] == '')
00143                         {
00144                                 $this->set_error('The following required POST variable is missing: '.$val);
00145                                 return FALSE;
00146                         }
00147                         
00148                         $this->data['charset'] = ( ! isset($_POST['charset'])) ? 'auto' : strtoupper(trim($_POST['charset']));
00149         
00150                         if ($val != 'url' && function_exists('mb_convert_encoding'))
00151                         {
00152                                 $_POST[$val] = mb_convert_encoding($_POST[$val], $this->charset, $this->data['charset']);
00153                         }
00154                         
00155                         $_POST[$val] = ($val != 'url') ? $this->convert_xml(strip_tags($_POST[$val])) : strip_tags($_POST[$val]);
00156                         
00157                         if ($val == 'excerpt')
00158                         {
00159                                 $_POST['excerpt'] = $this->limit_characters($_POST['excerpt']);
00160                         }
00161                         
00162                         $this->data[$val] = $_POST[$val];
00163                 }
00164 
00165                 return TRUE;
00166         }       
00167         
00168         // --------------------------------------------------------------------
00169         
00170         /**
00171          * Send Trackback Error Message
00172          *
00173          * Allows custom errors to be set.  By default it
00174          * sends the "incomplete information" error, as that's
00175          * the most common one.
00176          *
00177          * @access      public
00178          * @param       string
00179          * @return      void
00180          */     
00181         function send_error($message = 'Incomplete Information')
00182         {
00183                 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?".">\n<response>\n<error>1</error>\n<message>".$message."</message>\n</response>";
00184                 exit;
00185         }
00186         
00187         // --------------------------------------------------------------------
00188         
00189         /**
00190          * Send Trackback Success Message
00191          *
00192          * This should be called when a trackback has been
00193          * successfully received and inserted.
00194          *
00195          * @access      public
00196          * @return      void
00197          */             
00198         function send_success()
00199         {
00200                 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?".">\n<response>\n<error>0</error>\n</response>";
00201                 exit;
00202         }
00203         
00204         // --------------------------------------------------------------------
00205         
00206         /**
00207          * Fetch a particular item
00208          *
00209          * @access      public
00210          * @param       string
00211          * @return      string
00212          */     
00213         function data($item)
00214         {
00215                 return ( ! isset($this->data[$item])) ? '' : $this->data[$item];
00216         }
00217 
00218         // --------------------------------------------------------------------
00219         
00220         /**
00221          * Process Trackback
00222          *
00223          * Opens a socket connection and passes the data to
00224          * the server.  Returns true on success, false on failure
00225          *
00226          * @access      public
00227          * @param       string
00228          * @param       string
00229          * @return      bool
00230          */     
00231         function process($url, $data)
00232         {
00233                 $target = parse_url($url);
00234         
00235                 // Open the socket
00236                 if ( ! $fp = @fsockopen($target['host'], 80))
00237                 {
00238                         $this->set_error('Invalid Connection: '.$url);
00239                         return FALSE;
00240                 }
00241 
00242                 // Build the path
00243                 $ppath = ( ! isset($target['path'])) ? $url : $target['path'];
00244                 
00245                 $path = (isset($target['query']) && $target['query'] != "") ? $ppath.'?'.$target['query'] : $ppath;
00246 
00247                 // Add the Trackback ID to the data string
00248                 if ($id = $this->get_id($url))
00249                 {
00250                         $data = "tb_id=".$id."&".$data;
00251                 }
00252 
00253                 // Transfer the data
00254                 fputs ($fp, "POST " . $path . " HTTP/1.0\r\n" );
00255                 fputs ($fp, "Host: " . $target['host'] . "\r\n" );
00256                 fputs ($fp, "Content-type: application/x-www-form-urlencoded\r\n" );
00257                 fputs ($fp, "Content-length: " . strlen($data) . "\r\n" );
00258                 fputs ($fp, "Connection: close\r\n\r\n" );
00259                 fputs ($fp, $data);
00260 
00261                 // Was it successful?
00262                 $this->response = "";
00263                 
00264                 while( ! feof($fp))
00265                 {
00266                         $this->response .= fgets($fp, 128);
00267                 }
00268                 @fclose($fp);
00269                 
00270                 if ( ! eregi("<error>0</error>", $this->response))
00271                 {
00272                         $message = 'An unknown error was encountered';
00273                         
00274                         if (preg_match("/<message>(.*?)<\/message>/is", $this->response, $match))
00275                         {
00276                                 $message = trim($match['1']);
00277                         }
00278                         
00279                         $this->set_error($message);
00280                         return FALSE;
00281                 }
00282 
00283                 return TRUE;
00284         }
00285         
00286         // --------------------------------------------------------------------
00287         
00288         /**
00289          * Extract Trackback URLs
00290          *
00291          * This function lets multiple trackbacks be sent.
00292          * It takes a string of URLs (separated by comma or
00293          * space) and puts each URL into an array
00294          *
00295          * @access      public
00296          * @param       string
00297          * @return      string
00298          */     
00299         function extract_urls($urls)
00300         {               
00301                 // Remove the pesky white space and replace with a comma.
00302                 $urls = preg_replace("/\s*(\S+)\s*/", "\\1,", $urls);
00303                 
00304                 // If they use commas get rid of the doubles.
00305                 $urls = str_replace(",,", ",", $urls);
00306                 
00307                 // Remove any comma that might be at the end
00308                 if (substr($urls, -1) == ",")
00309                 {
00310                         $urls = substr($urls, 0, -1);
00311                 }
00312                                 
00313                 // Break into an array via commas
00314                 $urls = preg_split('/[,]/', $urls);
00315                 
00316                 // Removes duplicates
00317                 $urls = array_unique($urls);
00318                 
00319                 array_walk($urls, array($this, 'validate_url'));
00320                 
00321                 return $urls;
00322         }
00323         
00324         // --------------------------------------------------------------------
00325         
00326         /**
00327          * Validate URL
00328          *
00329          * Simply adds "http://" if missing
00330          *
00331          * @access      public
00332          * @param       string
00333          * @return      string
00334          */     
00335         function validate_url($url)
00336         {
00337                 $url = trim($url);
00338 
00339                 if (substr($url, 0, 4) != "http")
00340                 {
00341                         $url = "http://".$url;
00342                 }
00343         }
00344         
00345         // --------------------------------------------------------------------
00346         
00347         /**
00348          * Find the Trackback URL's ID
00349          *
00350          * @access      public
00351          * @param       string
00352          * @return      string
00353          */     
00354         function get_id($url)
00355         {       
00356                 $tb_id = "";
00357                 
00358                 if (strstr($url, '?'))
00359                 {
00360                         $tb_array = explode('/', $url);
00361                         $tb_end   = $tb_array[count($tb_array)-1];
00362                         
00363                         if ( ! is_numeric($tb_end))
00364                         {
00365                                 $tb_end  = $tb_array[count($tb_array)-2];
00366                         }
00367                         
00368                         $tb_array = explode('=', $tb_end);
00369                         $tb_id  = $tb_array[count($tb_array)-1];
00370                 }
00371                 else
00372                 {
00373                         if (ereg("/$", $url))
00374                         {
00375                                 $url = substr($url, 0, -1);
00376                         }
00377                                 
00378                         $tb_array = explode('/', $url);
00379                         $tb_id  = $tb_array[count($tb_array)-1];
00380                         
00381                         if ( ! is_numeric($tb_id))
00382                         {
00383                                 $tb_id  = $tb_array[count($tb_array)-2];
00384                         }
00385                 }       
00386                                 
00387                 if ( ! preg_match ("/^([0-9]+)$/", $tb_id))
00388                 {
00389                         return false;
00390                 }
00391                 else
00392                 {
00393                         return $tb_id;
00394                 }               
00395         }
00396         
00397         // --------------------------------------------------------------------
00398         
00399         /**
00400          * Convert Reserved XML characters to Entities
00401          *
00402          * @access      public
00403          * @param       string
00404          * @return      string
00405          */
00406         function convert_xml($str)
00407         {
00408                 $temp = '__TEMP_AMPERSANDS__';
00409                 
00410                 $str = preg_replace("/&#(\d+);/", "$temp\\1;", $str);
00411                 $str = preg_replace("/&(\w+);/",  "$temp\\1;", $str);
00412                 
00413                 $str = str_replace(array("&","<",">","\"", "'", "-"),
00414                                                    array("&amp;", "&lt;", "&gt;", "&quot;", "&#39;", "&#45;"),
00415                                                    $str);
00416                         
00417                 $str = preg_replace("/$temp(\d+);/","&#\\1;",$str);
00418                 $str = preg_replace("/$temp(\w+);/","&\\1;", $str);
00419                         
00420                 return $str;
00421         }       
00422         
00423         // --------------------------------------------------------------------
00424         
00425         /**
00426          * Character limiter
00427          *
00428          * Limits the string based on the character count. Will preserve complete words.
00429          *
00430          * @access      public
00431          * @param       string
00432          * @param       integer
00433          * @param       string
00434          * @return      string
00435          */
00436         function limit_characters($str, $n = 500, $end_char = '&#8230;')
00437         {
00438                 if (strlen($str) < $n)
00439                 {
00440                         return $str;
00441                 }
00442 
00443                 $str = preg_replace("/\s+/", ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
00444         
00445                 if (strlen($str) <= $n)
00446                 {
00447                         return $str;
00448                 }
00449                                                                                 
00450                 $out = "";
00451                 foreach (explode(' ', trim($str)) as $val)
00452                 {
00453                         $out .= $val.' ';                       
00454                         if (strlen($out) >= $n)
00455                         {
00456                                 return trim($out).$end_char;
00457                         }               
00458                 }
00459         }
00460         
00461         // --------------------------------------------------------------------
00462         
00463         /**
00464          * High ASCII to Entities
00465          *
00466          * Converts Hight ascii text and MS Word special chars
00467          * to character entities
00468          *
00469          * @access      public
00470          * @param       string
00471          * @return      string
00472          */
00473         function convert_ascii($str)
00474         {
00475            $count       = 1;
00476            $out = '';
00477            $temp        = array();
00478                 
00479            for ($i = 0, $s = strlen($str); $i < $s; $i++)
00480            {
00481                    $ordinal = ord($str[$i]);
00482                 
00483                    if ($ordinal < 128)
00484                    {
00485                            $out .= $str[$i];                    
00486                    }
00487                    else
00488                    {
00489                            if (count($temp) == 0)
00490                            {
00491                                    $count = ($ordinal < 224) ? 2 : 3;
00492                            }
00493                         
00494                            $temp[] = $ordinal;
00495                         
00496                            if (count($temp) == $count)
00497                            {
00498                                    $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64);
00499         
00500                                    $out .= '&#'.$number.';';
00501                                    $count = 1;
00502                                    $temp = array();
00503                            }
00504                    }
00505            }
00506         
00507            return $out;
00508         }
00509         
00510         // --------------------------------------------------------------------
00511         
00512         /**
00513          * Set error message
00514          *
00515          * @access      public
00516          * @param       string
00517          * @return      void
00518          */     
00519         function set_error($msg)
00520         {
00521                 log_message('error', $msg);
00522                 $this->error_msg[] = $msg;
00523         }
00524         
00525         // --------------------------------------------------------------------
00526         
00527         /**
00528          * Show error messages
00529          *
00530          * @access      public
00531          * @param       string
00532          * @param       string
00533          * @return      string
00534          */     
00535         function display_errors($open = '<p>', $close = '</p>')
00536         {       
00537                 $str = '';
00538                 foreach ($this->error_msg as $val)
00539                 {
00540                         $str .= $open.$val.$close;
00541                 }
00542         
00543                 return $str;
00544         }
00545 
00546 }
00547 // END Trackback Class
00548 
00549 /* End of file Trackback.php */
00550 /* Location: ./system/libraries/Trackback.php */