Pingback Server PHP Implementation


<?php
#require('../include/db.php');

set_error_handler("rpcErrorHandler");
error_reporting(E_ERROR | E_PARSE | E_COMPILE_ERROR | E_COMPILE_WARNING | E_CORE_ERROR | E_CORE_WARNING);

function rpcErrorHandler($errorcode, $errordescription, $filename, $linenumber, $context) {
    switch ($errorcode) {
    case E_NOTICE:
    case E_WARNING:
        break;
    default:
        $body = "Error code: $errorcode\n";
        $body .= "Error description: $errordescription\n";
        $body .= "Error occured in: $filename, line $linenumber\n";
        errorlog($body);
        header('Content-type: text/xml; charset=utf-8');
        ?>
        <methodResponse>
            <fault>
                <value>
                    <struct>
                        <member>
                            <name>faultCode</name>
                            <value><int>0</int></value>
                        </member>
                        <member>
                            <name>faultString</name>
                            <value>
                                <string>
                                    Error code: <?=$errorcode?>.
                                    Error description: <?=$errordescription?>.
                                    Error occured in: <?=$filename?>, line <?=$linenumber?>.
                                </string>
                            </value>
                        </member>
                    </struct>
                </value>
            </fault>
        </methodResponse>
        <?php
        die();
    }
}

function errorlog($msg) {
    global $db;
    $query = "INSERT INTO weblog_logs (date, message) VALUES (NOW(), '".$db->escape_string($msg)."')";
    $db->query($query);
}

function pingback($method, $params, $extra) {
    global $db;
    $sourceURI = $params[0];
    $targetURI = $params[1];
    $creq = curl_init();
    curl_setopt($creq, CURLOPT_URL, $sourceURI);
    curl_setopt($creq, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($creq, CURLOPT_TIMEOUT, 15);
    if(!$data = curl_exec($creq)) {
        // This page they claim they're linking to me from, it doesn't exist!  That can't be right.
        $error = "Source URI (".$sourceURI.") does not exist (target URI was ".$targetURI.")";
        errorLog($error);
        return array('faultCode' => 0x0010, 'faultString' => $error);
    }
    if(!strstr($data, htmlspecialchars($targetURI))) {
        // Doesn't contain a valid link
        if(!strstr($data, $targetURI)) {
            // Doesn't contain an invalid link either!
            $error = "Source URI (".$sourceURI.") does not contain a link to the target URI (".$targetURI.")";
            errorLog($error);
            return array('faultCode' => 0x0011, 'faultString' => $error);
        }
    }
    if(preg_match("/<title>([^<]*)<\/title>/i", $data, $matches)) {
        $title = $matches[1];
    } else {
        $title = '';
    }
    curl_close($creq);
    #user_error("/".preg_quote(HTTPLOC, '/')."weblog\/([0-9]{4})\/([0-9]{2})\/([0-9]{2})\/([^\"]*)/"); die;
    if(!preg_match("/".preg_quote(HTTPLOC, '/')."weblog\/([0-9]{4})\/([0-9]{2})\/([0-9]{2})\/([^\"]*)/", $targetURI, $target)) {
        // The URI given was not recognised as being that of a blog post on this site.
        $error = "Specified target URI (".$targetURI.") cannot be used as a target (source URI was ".$sourceURI.")";
        errorLog($error);
        return array('faultCode' => 0x0021, 'faultString' => $error);
    }
    $query = "SELECT entryid FROM weblog_entries ";
    $query .= "WHERE YEAR(weblog_entries.date) = $target[1] ";
    $query .= "AND MONTH(weblog_entries.date) = $target[2] ";
    $query .= "AND DAYOFMONTH(weblog_entries.date) = $target[3] ";
    $query .= "AND shorttopic = '".$db->escape_string($target[4])."' ";
    $rdsBlog = $db->query($query);
    if($rdBlog = $rdsBlog->fetch_assoc()) {
        $targetid = $rdBlog['entryid'];
    } else {
        // A blog entry was specified that doesn't exist!
        $error = "Specified target URI (".$targetURI.") does not exist (source URI was ".$sourceURI.")";
        errorLog($error);
        return array('faultCode' => 0x0020, 'faultString' => $error);
    }
    $query = "SELECT COUNT(*) AS number FROM weblog_xrefs ";
    $query .= "WHERE sourceURI = '".$db->escape_string(preg_replace("/&(amp;)?/i","&amp;",$sourceURI))."' AND entryid = ".$targetid;
    $rdsPb = $db->query($query);
    $rdPb = $rdsPb->fetch_assoc();
    if($rdPb['number'] > 0) {
        // They've already pingbacked/trackbacked this post once from this source URI.  No more!!!
        $error = "The pingback from ".$sourceURI." to ".$targetURI." has already been registered";
        errorLog($error);
        return array('faultCode' => 0x0030, 'faultString' => $error);
    }
    $query = "INSERT INTO weblog_xrefs (type, date, sourceURI, entryid, title) ";
    $query .= "VALUES ('Pingback', '".gmdate('Y-m-d H:i:s')."', '".$db->escape_string(preg_replace("/&(amp;)?/i","&amp;",$sourceURI))."', ".$targetid.", ";
    $query .= "'".$db->escape_string($title)."')";
    $db->query($query);

    // Yay! We done it! We is l33t!
    $message = "Thanks! Pingback from $sourceURI to $targetURI registered";
    errorLog($message);
    return $message;
}

$server = xmlrpc_server_create();
xmlrpc_server_register_method($server, 'pingback.ping', 'pingback');

// Process request
$request = file_get_contents("php://input");
$options = array('escaping' => 'markup', 'encoding' => 'utf-8');
$response = xmlrpc_server_call_method($server, $request, null, $options);

// Output response
header('Content-type: application/xml; charset=utf-8');
echo $response;

// Clean up
xmlrpc_server_destroy($server);

exit;
?>