PageRenderTime 67ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/system/libraries/Trackback.php

https://github.com/dchill42/CodeIgniter
PHP | 539 lines | 246 code | 83 blank | 210 comment | 27 complexity | 39c25220cd311c11cb33510c45b403f4 MD5 | raw file
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP 5.2.4 or newer
  6. *
  7. * NOTICE OF LICENSE
  8. *
  9. * Licensed under the Open Software License version 3.0
  10. *
  11. * This source file is subject to the Open Software License (OSL 3.0) that is
  12. * bundled with this package in the files license.txt / license.rst. It is
  13. * also available through the world wide web at this URL:
  14. * http://opensource.org/licenses/OSL-3.0
  15. * If you did not receive a copy of the license and are unable to obtain it
  16. * through the world wide web, please send an email to
  17. * licensing@ellislab.com so we can send you a copy immediately.
  18. *
  19. * @package CodeIgniter
  20. * @author EllisLab Dev Team
  21. * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  22. * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  23. * @link http://codeigniter.com
  24. * @since Version 1.0
  25. * @filesource
  26. */
  27. defined('BASEPATH') OR exit('No direct script access allowed');
  28. /**
  29. * Trackback Class
  30. *
  31. * Trackback Sending/Receiving Class
  32. *
  33. * @package CodeIgniter
  34. * @subpackage Libraries
  35. * @category Trackbacks
  36. * @author EllisLab Dev Team
  37. * @link http://codeigniter.com/user_guide/libraries/trackback.html
  38. */
  39. class CI_Trackback {
  40. /**
  41. * Character set
  42. *
  43. * @var string
  44. */
  45. public $charset = 'UTF-8';
  46. /**
  47. * Trackback data
  48. *
  49. * @var array
  50. */
  51. public $data = array('url' => '', 'title' => '', 'excerpt' => '', 'blog_name' => '', 'charset' => '');
  52. /**
  53. * Convert ASCII flag
  54. *
  55. * Whether to convert high-ASCII and MS Word
  56. * characters to HTML entities.
  57. *
  58. * @var bool
  59. */
  60. public $convert_ascii = TRUE;
  61. /**
  62. * Response
  63. *
  64. * @var string
  65. */
  66. public $response = '';
  67. /**
  68. * Error messages list
  69. *
  70. * @var string[]
  71. */
  72. public $error_msg = array();
  73. // --------------------------------------------------------------------
  74. /**
  75. * Constructor
  76. *
  77. * @return void
  78. */
  79. public function __construct()
  80. {
  81. log_message('debug', 'Trackback Class Initialized');
  82. }
  83. // --------------------------------------------------------------------
  84. /**
  85. * Send Trackback
  86. *
  87. * @param array
  88. * @return bool
  89. */
  90. public function send($tb_data)
  91. {
  92. if ( ! is_array($tb_data))
  93. {
  94. $this->set_error('The send() method must be passed an array');
  95. return FALSE;
  96. }
  97. // Pre-process the Trackback Data
  98. foreach (array('url', 'title', 'excerpt', 'blog_name', 'ping_url') as $item)
  99. {
  100. if ( ! isset($tb_data[$item]))
  101. {
  102. $this->set_error('Required item missing: '.$item);
  103. return FALSE;
  104. }
  105. switch ($item)
  106. {
  107. case 'ping_url' : $$item = $this->extract_urls($tb_data[$item]);
  108. break;
  109. case 'excerpt' : $$item = $this->limit_characters($this->convert_xml(strip_tags(stripslashes($tb_data[$item]))));
  110. break;
  111. case 'url' : $$item = str_replace('&#45;', '-', $this->convert_xml(strip_tags(stripslashes($tb_data[$item]))));
  112. break;
  113. default : $$item = $this->convert_xml(strip_tags(stripslashes($tb_data[$item])));
  114. break;
  115. }
  116. // Convert High ASCII Characters
  117. if ($this->convert_ascii === TRUE && in_array($item, array('excerpt', 'title', 'blog_name')))
  118. {
  119. $$item = $this->convert_ascii($$item);
  120. }
  121. }
  122. // Build the Trackback data string
  123. $charset = isset($tb_data['charset']) ? $tb_data['charset'] : $this->charset;
  124. $data = 'url='.rawurlencode($url).'&title='.rawurlencode($title).'&blog_name='.rawurlencode($blog_name)
  125. .'&excerpt='.rawurlencode($excerpt).'&charset='.rawurlencode($charset);
  126. // Send Trackback(s)
  127. $return = TRUE;
  128. if (count($ping_url) > 0)
  129. {
  130. foreach ($ping_url as $url)
  131. {
  132. if ($this->process($url, $data) === FALSE)
  133. {
  134. $return = FALSE;
  135. }
  136. }
  137. }
  138. return $return;
  139. }
  140. // --------------------------------------------------------------------
  141. /**
  142. * Receive Trackback Data
  143. *
  144. * This function simply validates the incoming TB data.
  145. * It returns FALSE on failure and TRUE on success.
  146. * If the data is valid it is set to the $this->data array
  147. * so that it can be inserted into a database.
  148. *
  149. * @return bool
  150. */
  151. public function receive()
  152. {
  153. foreach (array('url', 'title', 'blog_name', 'excerpt') as $val)
  154. {
  155. if (empty($_POST[$val]))
  156. {
  157. $this->set_error('The following required POST variable is missing: '.$val);
  158. return FALSE;
  159. }
  160. $this->data['charset'] = isset($_POST['charset']) ? strtoupper(trim($_POST['charset'])) : 'auto';
  161. if ($val !== 'url' && MB_ENABLED === TRUE)
  162. {
  163. $_POST[$val] = mb_convert_encoding($_POST[$val], $this->charset, $this->data['charset']);
  164. }
  165. $_POST[$val] = ($val !== 'url') ? $this->convert_xml(strip_tags($_POST[$val])) : strip_tags($_POST[$val]);
  166. if ($val === 'excerpt')
  167. {
  168. $_POST['excerpt'] = $this->limit_characters($_POST['excerpt']);
  169. }
  170. $this->data[$val] = $_POST[$val];
  171. }
  172. return TRUE;
  173. }
  174. // --------------------------------------------------------------------
  175. /**
  176. * Send Trackback Error Message
  177. *
  178. * Allows custom errors to be set. By default it
  179. * sends the "incomplete information" error, as that's
  180. * the most common one.
  181. *
  182. * @param string
  183. * @return void
  184. */
  185. public function send_error($message = 'Incomplete Information')
  186. {
  187. echo '<?xml version="1.0" encoding="utf-8"?'.">\n<response>\n<error>1</error>\n<message>".$message."</message>\n</response>";
  188. exit;
  189. }
  190. // --------------------------------------------------------------------
  191. /**
  192. * Send Trackback Success Message
  193. *
  194. * This should be called when a trackback has been
  195. * successfully received and inserted.
  196. *
  197. * @return void
  198. */
  199. public function send_success()
  200. {
  201. echo '<?xml version="1.0" encoding="utf-8"?'.">\n<response>\n<error>0</error>\n</response>";
  202. exit;
  203. }
  204. // --------------------------------------------------------------------
  205. /**
  206. * Fetch a particular item
  207. *
  208. * @param string
  209. * @return string
  210. */
  211. public function data($item)
  212. {
  213. return isset($this->data[$item]) ? $this->data[$item] : '';
  214. }
  215. // --------------------------------------------------------------------
  216. /**
  217. * Process Trackback
  218. *
  219. * Opens a socket connection and passes the data to
  220. * the server. Returns TRUE on success, FALSE on failure
  221. *
  222. * @param string
  223. * @param string
  224. * @return bool
  225. */
  226. public function process($url, $data)
  227. {
  228. $target = parse_url($url);
  229. // Open the socket
  230. if ( ! $fp = @fsockopen($target['host'], 80))
  231. {
  232. $this->set_error('Invalid Connection: '.$url);
  233. return FALSE;
  234. }
  235. // Build the path
  236. $ppath = isset($target['path']) ? $target['path'] : $url;
  237. $path = empty($target['query']) ? $ppath : $ppath.'?'.$target['query'];
  238. // Add the Trackback ID to the data string
  239. if ($id = $this->get_id($url))
  240. {
  241. $data = 'tb_id='.$id.'&'.$data;
  242. }
  243. // Transfer the data
  244. fputs($fp, 'POST '.$path." HTTP/1.0\r\n");
  245. fputs($fp, 'Host: '.$target['host']."\r\n");
  246. fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
  247. fputs($fp, 'Content-length: '.strlen($data)."\r\n");
  248. fputs($fp, "Connection: close\r\n\r\n");
  249. fputs($fp, $data);
  250. // Was it successful?
  251. $this->response = '';
  252. while ( ! feof($fp))
  253. {
  254. $this->response .= fgets($fp, 128);
  255. }
  256. @fclose($fp);
  257. if (stripos($this->response, '<error>0</error>') === FALSE)
  258. {
  259. $message = preg_match('/<message>(.*?)<\/message>/is', $this->response, $match) ? trim($match[1]) : 'An unknown error was encountered';
  260. $this->set_error($message);
  261. return FALSE;
  262. }
  263. return TRUE;
  264. }
  265. // --------------------------------------------------------------------
  266. /**
  267. * Extract Trackback URLs
  268. *
  269. * This function lets multiple trackbacks be sent.
  270. * It takes a string of URLs (separated by comma or
  271. * space) and puts each URL into an array
  272. *
  273. * @param string
  274. * @return string
  275. */
  276. public function extract_urls($urls)
  277. {
  278. // Remove the pesky white space and replace with a comma, then replace doubles.
  279. $urls = str_replace(',,', ',', preg_replace('/\s*(\S+)\s*/', '\\1,', $urls));
  280. // Remove any comma that might be at the end
  281. if (substr($urls, -1) === ',')
  282. {
  283. $urls = substr($urls, 0, -1);
  284. }
  285. // Break into an array via commas and remove duplicates
  286. $urls = array_unique(preg_split('/[,]/', $urls));
  287. array_walk($urls, array($this, 'validate_url'));
  288. return $urls;
  289. }
  290. // --------------------------------------------------------------------
  291. /**
  292. * Validate URL
  293. *
  294. * Simply adds "http://" if missing
  295. *
  296. * @param string
  297. * @return void
  298. */
  299. public function validate_url(&$url)
  300. {
  301. $url = trim($url);
  302. if (strpos($url, 'http') !== 0)
  303. {
  304. $url = 'http://'.$url;
  305. }
  306. }
  307. // --------------------------------------------------------------------
  308. /**
  309. * Find the Trackback URL's ID
  310. *
  311. * @param string
  312. * @return string
  313. */
  314. public function get_id($url)
  315. {
  316. $tb_id = '';
  317. if (strpos($url, '?') !== FALSE)
  318. {
  319. $tb_array = explode('/', $url);
  320. $tb_end = $tb_array[count($tb_array)-1];
  321. if ( ! is_numeric($tb_end))
  322. {
  323. $tb_end = $tb_array[count($tb_array)-2];
  324. }
  325. $tb_array = explode('=', $tb_end);
  326. $tb_id = $tb_array[count($tb_array)-1];
  327. }
  328. else
  329. {
  330. $url = rtrim($url, '/');
  331. $tb_array = explode('/', $url);
  332. $tb_id = $tb_array[count($tb_array)-1];
  333. if ( ! is_numeric($tb_id))
  334. {
  335. $tb_id = $tb_array[count($tb_array)-2];
  336. }
  337. }
  338. return ctype_digit((string) $tb_id) ? $tb_id : FALSE;
  339. }
  340. // --------------------------------------------------------------------
  341. /**
  342. * Convert Reserved XML characters to Entities
  343. *
  344. * @param string
  345. * @return string
  346. */
  347. public function convert_xml($str)
  348. {
  349. $temp = '__TEMP_AMPERSANDS__';
  350. $str = preg_replace(array('/&#(\d+);/', '/&(\w+);/'), $temp.'\\1;', $str);
  351. $str = str_replace(array('&', '<', '>', '"', "'", '-'),
  352. array('&amp;', '&lt;', '&gt;', '&quot;', '&#39;', '&#45;'),
  353. $str);
  354. return preg_replace(array('/'.$temp.'(\d+);/', '/'.$temp.'(\w+);/'), array('&#\\1;', '&\\1;'), $str);
  355. }
  356. // --------------------------------------------------------------------
  357. /**
  358. * Character limiter
  359. *
  360. * Limits the string based on the character count. Will preserve complete words.
  361. *
  362. * @param string
  363. * @param int
  364. * @param string
  365. * @return string
  366. */
  367. public function limit_characters($str, $n = 500, $end_char = '&#8230;')
  368. {
  369. if (strlen($str) < $n)
  370. {
  371. return $str;
  372. }
  373. $str = preg_replace('/\s+/', ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
  374. if (strlen($str) <= $n)
  375. {
  376. return $str;
  377. }
  378. $out = '';
  379. foreach (explode(' ', trim($str)) as $val)
  380. {
  381. $out .= $val.' ';
  382. if (strlen($out) >= $n)
  383. {
  384. return rtrim($out).$end_char;
  385. }
  386. }
  387. }
  388. // --------------------------------------------------------------------
  389. /**
  390. * High ASCII to Entities
  391. *
  392. * Converts Hight ascii text and MS Word special chars
  393. * to character entities
  394. *
  395. * @param string
  396. * @return string
  397. */
  398. public function convert_ascii($str)
  399. {
  400. $count = 1;
  401. $out = '';
  402. $temp = array();
  403. for ($i = 0, $s = strlen($str); $i < $s; $i++)
  404. {
  405. $ordinal = ord($str[$i]);
  406. if ($ordinal < 128)
  407. {
  408. $out .= $str[$i];
  409. }
  410. else
  411. {
  412. if (count($temp) === 0)
  413. {
  414. $count = ($ordinal < 224) ? 2 : 3;
  415. }
  416. $temp[] = $ordinal;
  417. if (count($temp) === $count)
  418. {
  419. $number = ($count === 3)
  420. ? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64)
  421. : (($temp[0] % 32) * 64) + ($temp[1] % 64);
  422. $out .= '&#'.$number.';';
  423. $count = 1;
  424. $temp = array();
  425. }
  426. }
  427. }
  428. return $out;
  429. }
  430. // --------------------------------------------------------------------
  431. /**
  432. * Set error message
  433. *
  434. * @param string
  435. * @return void
  436. */
  437. public function set_error($msg)
  438. {
  439. log_message('error', $msg);
  440. $this->error_msg[] = $msg;
  441. }
  442. // --------------------------------------------------------------------
  443. /**
  444. * Show error messages
  445. *
  446. * @param string
  447. * @param string
  448. * @return string
  449. */
  450. public function display_errors($open = '<p>', $close = '</p>')
  451. {
  452. return (count($this->error_msg) > 0) ? $open.implode($close.$open, $this->error_msg).$close : '';
  453. }
  454. }
  455. /* End of file Trackback.php */
  456. /* Location: ./system/libraries/Trackback.php */