| Current Path : /home/m/a/g/magalijoj/www/blog/inc/core/ |
| Current File : /home/m/a/g/magalijoj/www/blog/inc/core/class.dc.trackback.php |
<?php
# ***** BEGIN LICENSE BLOCK *****
# This file is part of DotClear.
# Copyright (c) 2005 Olivier Meunier. All rights
# reserved.
#
# DotClear is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# DotClear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with DotClear; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# ***** END LICENSE BLOCK *****
/**
@ingroup DC_CORE
@brief Trackbacks sender and server
Sends and receives trackbacks. Also handles trackbacks auto discovery.
*/
class dcTrackback
{
public $core; ///< <b>dcCore</b> dcCore instance
public $table; ///< <b>string</b> done pings table name
/**
Object constructor
@param core <b>dcCore</b> dcCore instance
*/
public function __construct(&$core)
{
$this->core =& $core;
$this->con =& $this->core->con;
$this->table = $this->core->prefix.'ping';
}
/// @name Send trackbacks
//@{
/**
Get all pings sent for a given post.
@param post_id <b>integer</b> Post ID
@return <b>record</b>
*/
public function getPostPings($post_id)
{
$strReq = 'SELECT ping_url, ping_dt '.
'FROM '.$this->table.' '.
'WHERE post_id = '.(integer) $post_id;
return $this->con->select($strReq);
}
/**
Sends a ping to given <var>$url</var>.
@param url <b>string</b> URL to ping
@param post_id <b>integer</b> Post ID
@param post_title <b>string</b> Post title
@param post_excerpt <b>string</b> Post excerpt
@param post_url <b>string</b> Post URL
*/
public function ping($url,$post_id,$post_title,$post_excerpt,$post_url)
{
if ($this->core->blog === null) {
return false;
}
$post_id = (integer) $post_id;
# Check for previously done trackback
$strReq = 'SELECT post_id, ping_url FROM '.$this->table.' '.
'WHERE post_id = '.$post_id.' '.
"AND ping_url = '".$this->con->escape($url)."' ";
$rs = $this->con->select($strReq);
if (!$rs->isEmpty()) {
throw new Exception(sprintf(__('%s has still been pinged'),$url));
}
$data = array(
'title' => $post_title,
'excerpt' => $post_excerpt,
'url' => $post_url,
'blog_name' => trim(html::escapeHTML(html::clean($this->core->blog->name)))
//,'__debug' => false
);
# Ping
try
{
$http = self::initHttp($url,$path);
$http->post($path,$data,'UTF-8');
$res = $http->getContent();
}
catch (Exception $e)
{
throw new Exception(__('Unable to ping URL'));
}
$pattern =
'|<response>.*<error>(.*)</error>(.*)'.
'(<message>(.*)</message>(.*))?'.
'</response>|msU';
if (!preg_match($pattern,$res,$match))
{
throw new Exception(sprintf(__('%s is not a ping URL'),$url));
}
$ping_error = trim($match[1]);
$ping_msg = (!empty($match[4])) ? $match[4] : '';
if ($ping_error != '0') {
throw new Exception(sprintf(__('%s, ping error:'),$url).' '.$ping_msg);
} else {
# Notify ping result in database
$cur = $this->con->openCursor($this->table);
$cur->post_id = $post_id;
$cur->ping_url = $url;
$cur->ping_dt = array('NOW()');
$cur->insert();
}
}
//@}
/// @name Receive trackbacks
//@{
/**
Receives a trackback and insert it as a comment of given post.
@param post_id <b>integer</b> Post ID
*/
public function receive($post_id)
{
header('Content-Type: text/xml; charset=UTF-8');
if (empty($_POST)) {
http::head(405,'Method Not Allowed');
echo
'<?xml version="1.0" encoding="utf-8"?>'."\n".
"<response>\n".
" <error>1</error>\n".
" <message>POST request needed</message>\n".
"</response>";
return;
}
$post_id = (integer) $post_id;
$title = !empty($_POST['title']) ? $_POST['title'] : '';
$excerpt = !empty($_POST['excerpt']) ? $_POST['excerpt'] : '';
$url = !empty($_POST['url']) ? $_POST['url'] : '';
$blog_name = !empty($_POST['blog_name']) ? $_POST['blog_name'] : '';
$charset = '';
$comment = '';
$err = false;
$msg = '';
if ($this->core->blog === null)
{
$err = true;
$msg = 'No blog.';
}
elseif ($url == '')
{
$err = true;
$msg = 'URL parameter is requiered.';
}
elseif ($blog_name == '') {
$err = true;
$msg = 'Blog name is requiered.';
}
if (!$err)
{
$post = $this->core->blog->getPosts(array('post_id'=>$post_id));
if ($post->isEmpty())
{
$err = true;
$msg = 'No such post.';
}
elseif (!$post->trackbacksActive())
{
$err = true;
$msg = 'Trackbacks are not allowed for this post or weblog.';
}
}
if (!$err)
{
$charset = self::getCharsetFromRequest();
if (!$charset) {
$charset = mb_detect_encoding($title.' '.$excerpt.' '.$blog_name,
'UTF-8,ISO-8859-1,ISO-8859-2,ISO-8859-3,'.
'ISO-8859-4,ISO-8859-5,ISO-8859-6,ISO-8859-7,ISO-8859-8,'.
'ISO-8859-9,ISO-8859-10,ISO-8859-13,ISO-8859-14,ISO-8859-15');
}
if (strtolower($charset) != 'utf-8') {
$title = iconv($charset,'UTF-8',$title);
$excerpt = iconv($charset,'UTF-8',$excerpt);
$blog_name = iconv($charset,'UTF-8',$blog_name);
}
$title = trim(html::clean($title));
$title = html::decodeEntities($title);
$title = html::escapeHTML($title);
$title = text::cutString($title,60);
$excerpt = trim(html::clean($excerpt));
$excerpt = html::decodeEntities($excerpt);
$excerpt = preg_replace('/\s+/ms',' ',$excerpt);
$excerpt = text::cutString($excerpt,252);
$excerpt = html::escapeHTML($excerpt).'...';
$blog_name = trim(html::clean($blog_name));
$blog_name = html::decodeEntities($blog_name);
$blog_name = html::escapeHTML($blog_name);
$blog_name = text::cutString($blog_name,60);
$url = trim(html::clean($url));
if (!$blog_name) {
$blog_name = 'Anonymous blog';
}
$comment =
"<!-- TB -->\n".
'<p><strong>'.($title ? $title : $blog_name)."</strong></p>\n".
'<p>'.$excerpt.'</p>';
$cur = $this->core->con->openCursor($this->core->prefix.'comment');
$cur->comment_author = (string) $blog_name;
$cur->comment_site = (string) $url;
$cur->comment_content = (string) $comment;
$cur->post_id = $post_id;
$cur->comment_trackback = 1;
$cur->comment_status = $this->core->blog->settings->trackbacks_pub ? 1 : -1;
$cur->comment_ip = http::realIP();
try
{
# --BEHAVIOR-- publicBeforeTrackbackCreate
$this->core->callBehavior('publicBeforeTrackbackCreate',$cur);
$comment_id = $this->core->blog->addComment($cur);
# --BEHAVIOR-- publicAfterTrackbackCreate
$this->core->callBehavior('publicAfterTrackbackCreate',$cur,$comment_id);
}
catch (Exception $e)
{
$err = 1;
$msg = 'Something went wrong : '.$e->getMessage();
}
}
$debug_trace =
" <debug>\n".
' <title>'.$title."</title>\n".
' <excerpt>'.$excerpt."</excerpt>\n".
' <url>'.$url."</url>\n".
' <blog_name>'.$blog_name."</blog_name>\n".
' <charset>'.$charset."</charset>\n".
' <comment>'.$comment."</comment>\n".
" </debug>\n";
$resp =
'<?xml version="1.0" encoding="utf-8"?>'."\n".
"<response>\n".
' <error>'.(integer) $err."</error>\n";
if ($msg) {
$resp .= ' <message>'.$msg."</message>\n";
}
if (!empty($_POST['__debug'])) {
$resp .= $debug_trace;
}
echo $resp."</response>";
}
//@}
private static function initHttp($url,&$path)
{
$client = netHttp::initClient($url,$path,5);
$client->setUserAgent('Dotclear - http://www.dotclear.net/');
$client->useGzip(false);
$client->setPersistReferers(false);
return $client;
}
private static function getCharsetFromRequest()
{
if (isset($_SERVER['CONTENT_TYPE']))
{
if (preg_match('|charset=([a-zA-Z0-9-]+)|',$_SERVER['CONTENT_TYPE'],$m)) {
return $m[1];
}
}
return null;
}
/// @name Trackbacks auto discovery
//@{
/**
Returns an array containing all discovered trackbacks URLs in
<var>$text</var>.
@param text <b>string</b> Input text
@return <b>array</b>
*/
public function discover($text)
{
$res = array();
foreach ($this->getTextLinks($text) as $link)
{
if (($url = $this->getPingURL($link)) !== null) {
$res[] = $url;
}
}
return $res;
}
//@}
private function getTextLinks($text)
{
$res = array();
# href attribute on "a" tags
if (preg_match_all('/<a ([^>]+)>/ms', $text, $match, PREG_SET_ORDER))
{
for ($i = 0; $i<count($match); $i++)
{
if (preg_match('/href="(http:\/\/[^"]+)"/ms', $match[$i][1], $matches)) {
$res[$matches[1]] = 1;
}
}
}
unset($match);
# cite attributes on "blockquote" and "q" tags
if (preg_match_all('/<(blockquote|q) ([^>]+)>/ms', $text, $match, PREG_SET_ORDER))
{
for ($i = 0; $i<count($match); $i++)
{
if (preg_match('/cite="(http:\/\/[^"]+)"/ms', $match[$i][2], $matches)) {
$res[$matches[1]] = 1;
}
}
}
return array_keys($res);
}
private function getPingURL($url)
{
try
{
$http = self::initHttp($url,$path);
$http->get($path);
$page_content = $http->getContent();
}
catch (Exception $e)
{
return false;
}
$pattern_rdf =
'/<rdf:RDF.*?>.*?'.
'<rdf:Description\s+(.*?)\/>'.
'.*?<\/rdf:RDF>'.
'/ms';
preg_match_all($pattern_rdf,$page_content,$rdf_all,PREG_SET_ORDER);
for ($i=0; $i<count($rdf_all); $i++)
{
$rdf = $rdf_all[$i][1];
if (preg_match('/dc:identifier="'.preg_quote($url,'/').'"/ms',$rdf)) {
if (preg_match('/trackback:ping="(.*?)"/ms',$rdf,$tb_link)) {
return $tb_link[1];
}
}
}
return null;
}
}
?>