You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
556 lines
13 KiB
556 lines
13 KiB
<?php |
|
/** |
|
* CodeIgniter |
|
* |
|
* An open source application development framework for PHP |
|
* |
|
* This content is released under the MIT License (MIT) |
|
* |
|
* Copyright (c) 2014 - 2016, British Columbia Institute of Technology |
|
* |
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
* of this software and associated documentation files (the "Software"), to deal |
|
* in the Software without restriction, including without limitation the rights |
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
* copies of the Software, and to permit persons to whom the Software is |
|
* furnished to do so, subject to the following conditions: |
|
* |
|
* The above copyright notice and this permission notice shall be included in |
|
* all copies or substantial portions of the Software. |
|
* |
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
* THE SOFTWARE. |
|
* |
|
* @package CodeIgniter |
|
* @author EllisLab Dev Team |
|
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) |
|
* @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/) |
|
* @license http://opensource.org/licenses/MIT MIT License |
|
* @link https://codeigniter.com |
|
* @since Version 1.0.0 |
|
* @filesource |
|
*/ |
|
defined('BASEPATH') OR exit('No direct script access allowed'); |
|
|
|
/** |
|
* Trackback Class |
|
* |
|
* Trackback Sending/Receiving Class |
|
* |
|
* @package CodeIgniter |
|
* @subpackage Libraries |
|
* @category Trackbacks |
|
* @author EllisLab Dev Team |
|
* @link https://codeigniter.com/user_guide/libraries/trackback.html |
|
*/ |
|
class CI_Trackback { |
|
|
|
/** |
|
* Character set |
|
* |
|
* @var string |
|
*/ |
|
public $charset = 'UTF-8'; |
|
|
|
/** |
|
* Trackback data |
|
* |
|
* @var array |
|
*/ |
|
public $data = array( |
|
'url' => '', |
|
'title' => '', |
|
'excerpt' => '', |
|
'blog_name' => '', |
|
'charset' => '' |
|
); |
|
|
|
/** |
|
* Convert ASCII flag |
|
* |
|
* Whether to convert high-ASCII and MS Word |
|
* characters to HTML entities. |
|
* |
|
* @var bool |
|
*/ |
|
public $convert_ascii = TRUE; |
|
|
|
/** |
|
* Response |
|
* |
|
* @var string |
|
*/ |
|
public $response = ''; |
|
|
|
/** |
|
* Error messages list |
|
* |
|
* @var string[] |
|
*/ |
|
public $error_msg = array(); |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Constructor |
|
* |
|
* @return void |
|
*/ |
|
public function __construct() |
|
{ |
|
log_message('info', 'Trackback Class Initialized'); |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Send Trackback |
|
* |
|
* @param array |
|
* @return bool |
|
*/ |
|
public function send($tb_data) |
|
{ |
|
if ( ! is_array($tb_data)) |
|
{ |
|
$this->set_error('The send() method must be passed an array'); |
|
return FALSE; |
|
} |
|
|
|
// Pre-process the Trackback Data |
|
foreach (array('url', 'title', 'excerpt', 'blog_name', 'ping_url') as $item) |
|
{ |
|
if ( ! isset($tb_data[$item])) |
|
{ |
|
$this->set_error('Required item missing: '.$item); |
|
return FALSE; |
|
} |
|
|
|
switch ($item) |
|
{ |
|
case 'ping_url': |
|
$$item = $this->extract_urls($tb_data[$item]); |
|
break; |
|
case 'excerpt': |
|
$$item = $this->limit_characters($this->convert_xml(strip_tags(stripslashes($tb_data[$item])))); |
|
break; |
|
case 'url': |
|
$$item = str_replace('-', '-', $this->convert_xml(strip_tags(stripslashes($tb_data[$item])))); |
|
break; |
|
default: |
|
$$item = $this->convert_xml(strip_tags(stripslashes($tb_data[$item]))); |
|
break; |
|
} |
|
|
|
// Convert High ASCII Characters |
|
if ($this->convert_ascii === TRUE && in_array($item, array('excerpt', 'title', 'blog_name'), TRUE)) |
|
{ |
|
$$item = $this->convert_ascii($$item); |
|
} |
|
} |
|
|
|
// Build the Trackback data string |
|
$charset = isset($tb_data['charset']) ? $tb_data['charset'] : $this->charset; |
|
|
|
$data = 'url='.rawurlencode($url).'&title='.rawurlencode($title).'&blog_name='.rawurlencode($blog_name) |
|
.'&excerpt='.rawurlencode($excerpt).'&charset='.rawurlencode($charset); |
|
|
|
// Send Trackback(s) |
|
$return = TRUE; |
|
if (count($ping_url) > 0) |
|
{ |
|
foreach ($ping_url as $url) |
|
{ |
|
if ($this->process($url, $data) === FALSE) |
|
{ |
|
$return = FALSE; |
|
} |
|
} |
|
} |
|
|
|
return $return; |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Receive Trackback Data |
|
* |
|
* This function simply validates the incoming TB data. |
|
* It returns FALSE on failure and TRUE on success. |
|
* If the data is valid it is set to the $this->data array |
|
* so that it can be inserted into a database. |
|
* |
|
* @return bool |
|
*/ |
|
public function receive() |
|
{ |
|
foreach (array('url', 'title', 'blog_name', 'excerpt') as $val) |
|
{ |
|
if (empty($_POST[$val])) |
|
{ |
|
$this->set_error('The following required POST variable is missing: '.$val); |
|
return FALSE; |
|
} |
|
|
|
$this->data['charset'] = isset($_POST['charset']) ? strtoupper(trim($_POST['charset'])) : 'auto'; |
|
|
|
if ($val !== 'url' && MB_ENABLED === TRUE) |
|
{ |
|
if (MB_ENABLED === TRUE) |
|
{ |
|
$_POST[$val] = mb_convert_encoding($_POST[$val], $this->charset, $this->data['charset']); |
|
} |
|
elseif (ICONV_ENABLED === TRUE) |
|
{ |
|
$_POST[$val] = @iconv($this->data['charset'], $this->charset.'//IGNORE', $_POST[$val]); |
|
} |
|
} |
|
|
|
$_POST[$val] = ($val !== 'url') ? $this->convert_xml(strip_tags($_POST[$val])) : strip_tags($_POST[$val]); |
|
|
|
if ($val === 'excerpt') |
|
{ |
|
$_POST['excerpt'] = $this->limit_characters($_POST['excerpt']); |
|
} |
|
|
|
$this->data[$val] = $_POST[$val]; |
|
} |
|
|
|
return TRUE; |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Send Trackback Error Message |
|
* |
|
* Allows custom errors to be set. By default it |
|
* sends the "incomplete information" error, as that's |
|
* the most common one. |
|
* |
|
* @param string |
|
* @return void |
|
*/ |
|
public function send_error($message = 'Incomplete Information') |
|
{ |
|
exit('<?xml version="1.0" encoding="utf-8"?'.">\n<response>\n<error>1</error>\n<message>".$message."</message>\n</response>"); |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Send Trackback Success Message |
|
* |
|
* This should be called when a trackback has been |
|
* successfully received and inserted. |
|
* |
|
* @return void |
|
*/ |
|
public function send_success() |
|
{ |
|
exit('<?xml version="1.0" encoding="utf-8"?'.">\n<response>\n<error>0</error>\n</response>"); |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Fetch a particular item |
|
* |
|
* @param string |
|
* @return string |
|
*/ |
|
public function data($item) |
|
{ |
|
return isset($this->data[$item]) ? $this->data[$item] : ''; |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Process Trackback |
|
* |
|
* Opens a socket connection and passes the data to |
|
* the server. Returns TRUE on success, FALSE on failure |
|
* |
|
* @param string |
|
* @param string |
|
* @return bool |
|
*/ |
|
public function process($url, $data) |
|
{ |
|
$target = parse_url($url); |
|
|
|
// Open the socket |
|
if ( ! $fp = @fsockopen($target['host'], 80)) |
|
{ |
|
$this->set_error('Invalid Connection: '.$url); |
|
return FALSE; |
|
} |
|
|
|
// Build the path |
|
$path = isset($target['path']) ? $target['path'] : $url; |
|
empty($target['query']) OR $path .= '?'.$target['query']; |
|
|
|
// Add the Trackback ID to the data string |
|
if ($id = $this->get_id($url)) |
|
{ |
|
$data = 'tb_id='.$id.'&'.$data; |
|
} |
|
|
|
// Transfer the data |
|
fputs($fp, 'POST '.$path." HTTP/1.0\r\n"); |
|
fputs($fp, 'Host: '.$target['host']."\r\n"); |
|
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n"); |
|
fputs($fp, 'Content-length: '.strlen($data)."\r\n"); |
|
fputs($fp, "Connection: close\r\n\r\n"); |
|
fputs($fp, $data); |
|
|
|
// Was it successful? |
|
|
|
$this->response = ''; |
|
while ( ! feof($fp)) |
|
{ |
|
$this->response .= fgets($fp, 128); |
|
} |
|
@fclose($fp); |
|
|
|
if (stripos($this->response, '<error>0</error>') === FALSE) |
|
{ |
|
$message = preg_match('/<message>(.*?)<\/message>/is', $this->response, $match) |
|
? trim($match[1]) |
|
: 'An unknown error was encountered'; |
|
$this->set_error($message); |
|
return FALSE; |
|
} |
|
|
|
return TRUE; |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Extract Trackback URLs |
|
* |
|
* This function lets multiple trackbacks be sent. |
|
* It takes a string of URLs (separated by comma or |
|
* space) and puts each URL into an array |
|
* |
|
* @param string |
|
* @return string |
|
*/ |
|
public function extract_urls($urls) |
|
{ |
|
// Remove the pesky white space and replace with a comma, then replace doubles. |
|
$urls = str_replace(',,', ',', preg_replace('/\s*(\S+)\s*/', '\\1,', $urls)); |
|
|
|
// Break into an array via commas and remove duplicates |
|
$urls = array_unique(preg_split('/[,]/', rtrim($urls, ','))); |
|
|
|
array_walk($urls, array($this, 'validate_url')); |
|
return $urls; |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Validate URL |
|
* |
|
* Simply adds "http://" if missing |
|
* |
|
* @param string |
|
* @return void |
|
*/ |
|
public function validate_url(&$url) |
|
{ |
|
$url = trim($url); |
|
|
|
if (strpos($url, 'http') !== 0) |
|
{ |
|
$url = 'http://'.$url; |
|
} |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Find the Trackback URL's ID |
|
* |
|
* @param string |
|
* @return string |
|
*/ |
|
public function get_id($url) |
|
{ |
|
$tb_id = ''; |
|
|
|
if (strpos($url, '?') !== FALSE) |
|
{ |
|
$tb_array = explode('/', $url); |
|
$tb_end = $tb_array[count($tb_array)-1]; |
|
|
|
if ( ! is_numeric($tb_end)) |
|
{ |
|
$tb_end = $tb_array[count($tb_array)-2]; |
|
} |
|
|
|
$tb_array = explode('=', $tb_end); |
|
$tb_id = $tb_array[count($tb_array)-1]; |
|
} |
|
else |
|
{ |
|
$url = rtrim($url, '/'); |
|
|
|
$tb_array = explode('/', $url); |
|
$tb_id = $tb_array[count($tb_array)-1]; |
|
|
|
if ( ! is_numeric($tb_id)) |
|
{ |
|
$tb_id = $tb_array[count($tb_array)-2]; |
|
} |
|
} |
|
|
|
return ctype_digit((string) $tb_id) ? $tb_id : FALSE; |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Convert Reserved XML characters to Entities |
|
* |
|
* @param string |
|
* @return string |
|
*/ |
|
public function convert_xml($str) |
|
{ |
|
$temp = '__TEMP_AMPERSANDS__'; |
|
|
|
$str = preg_replace(array('/&#(\d+);/', '/&(\w+);/'), $temp.'\\1;', $str); |
|
|
|
$str = str_replace(array('&', '<', '>', '"', "'", '-'), |
|
array('&', '<', '>', '"', ''', '-'), |
|
$str); |
|
|
|
return preg_replace(array('/'.$temp.'(\d+);/', '/'.$temp.'(\w+);/'), array('&#\\1;', '&\\1;'), $str); |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Character limiter |
|
* |
|
* Limits the string based on the character count. Will preserve complete words. |
|
* |
|
* @param string |
|
* @param int |
|
* @param string |
|
* @return string |
|
*/ |
|
public function limit_characters($str, $n = 500, $end_char = '…') |
|
{ |
|
if (strlen($str) < $n) |
|
{ |
|
return $str; |
|
} |
|
|
|
$str = preg_replace('/\s+/', ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str)); |
|
|
|
if (strlen($str) <= $n) |
|
{ |
|
return $str; |
|
} |
|
|
|
$out = ''; |
|
foreach (explode(' ', trim($str)) as $val) |
|
{ |
|
$out .= $val.' '; |
|
if (strlen($out) >= $n) |
|
{ |
|
return rtrim($out).$end_char; |
|
} |
|
} |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* High ASCII to Entities |
|
* |
|
* Converts Hight ascii text and MS Word special chars |
|
* to character entities |
|
* |
|
* @param string |
|
* @return string |
|
*/ |
|
public function convert_ascii($str) |
|
{ |
|
$count = 1; |
|
$out = ''; |
|
$temp = array(); |
|
|
|
for ($i = 0, $s = strlen($str); $i < $s; $i++) |
|
{ |
|
$ordinal = ord($str[$i]); |
|
|
|
if ($ordinal < 128) |
|
{ |
|
$out .= $str[$i]; |
|
} |
|
else |
|
{ |
|
if (count($temp) === 0) |
|
{ |
|
$count = ($ordinal < 224) ? 2 : 3; |
|
} |
|
|
|
$temp[] = $ordinal; |
|
|
|
if (count($temp) === $count) |
|
{ |
|
$number = ($count === 3) |
|
? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64) |
|
: (($temp[0] % 32) * 64) + ($temp[1] % 64); |
|
|
|
$out .= '&#'.$number.';'; |
|
$count = 1; |
|
$temp = array(); |
|
} |
|
} |
|
} |
|
|
|
return $out; |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Set error message |
|
* |
|
* @param string |
|
* @return void |
|
*/ |
|
public function set_error($msg) |
|
{ |
|
log_message('error', $msg); |
|
$this->error_msg[] = $msg; |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Show error messages |
|
* |
|
* @param string |
|
* @param string |
|
* @return string |
|
*/ |
|
public function display_errors($open = '<p>', $close = '</p>') |
|
{ |
|
return (count($this->error_msg) > 0) ? $open.implode($close.$open, $this->error_msg).$close : ''; |
|
} |
|
|
|
}
|
|
|