PicoraPingBack

An implementation of the Pingback specification.

Method Overview

Return Visibility Name Parameters
array static public autoPing (string $from, string $text)
mixed static public discover (string $url)
array static public ping (string $server, string $from, string $to)

Method Detail

static public autoPing()

Parameter Type Name Description
string $from URL to scan
string $text Manually specify the page contents of the $from URL

Scrapes a given URL for links and sends PingBack pings from that URL to each of the links found.

static public discover()

Parameter Type Name Description
string $url Any given web page.

Find the XMLRPC endpoint of a given PingBack resource.

static public ping()

Parameter Type Name Description
string $server XMLRPC endpoint
string $from URL PingBack from
string $to URL PingBack from

Send a PingBack ping.

Declared in: PicoraPingBack.php

class PicoraPingBack {
    static public function viewHelper(){
        return '<link rel="pingback" href="'.PicoraDispatcher::getUrl(array('PicoraXMLRPC','respondToXMLRPC')).'" />';
    }
    static public function respondToGetPingsRequest($local){
        if(!self::getURL(addslashes($local)))
            return new IXR_Error(33,'Target does not exist on this server.');
        $list = array();
        foreach(PicoraPing::findAllByLocal($local) as $ping)
            $list[] = $ping->remote;
        return $list;
    }
    static public function respondToPingRequest($remote,$local){
        $remote = addslashes($remote);
        $local = addslashes($local);
        if(strpos(addslashes($local),preg_replace('|https?://|','',BASE_URL)) === false)
            return new IXR_Error(33,'Target does not exist on this server.');
        if($remote == $local)
            return new IXR_Error(33,'Remote and local must be distinct urls.');
        if(!self::getURL(addslashes($local)))
            return new IXR_Error(33,'Target does not exist on this server.');
        $ping = PicoraActiveRecord::find('PicoraPing',array(
            'where' => array(
                'local' => $local,
                'remote' => $remote
            )
        ));
        if($ping)
            return new IXR_Error(48,'The pingback is already registered.');
        sleep(1);        
        $remote_content = self::getURL($remote);
        if(!$remote_content)
            return new IXR_Error(16,'The source URL could not be found.');
        if(!in_array($local,self::scrape($remote_content)))
            return new IXR_Error(17,'The source URL does not contain a link to the target URI.');
        PicoraActiveRecord::create('PicoraPing',array(
            'name' => (preg_match('/<title>([^<]*?)<\/title>/is',$remote_content,$m) ? $m[1] : $remote),
            'local' => $local,
            'remote' => $remote
        ));
         return "Ping recorded.";
    }
    /**
     * Find the XMLRPC endpoint of a given PingBack resource.
     * @param string $url Any given web page.
     * @return mixed Returns the URL of the XMLRPC endpoint or false if it could not be found, or null if the URL could not be opened.
     */
    static public function discover($url){
        $contents = self::getURL($url,true,8192);
        if(!$contents)
            return null;
        if(preg_match('/X-Pingback: (.+)/',$contents,$match))
            return $match[1];
         if(preg_match('/<link rel="pingback" href="(.+?)"/',$contents,$match))
             return urldecode(html_entity_decode($match[1]));
        return false;
    }
    /**
     * Send a PingBack ping.
     * @param string $server XMLRPC endpoint
     * @param string $from URL PingBack from
     * @param string $to URL PingBack from
     * @return array (bool success,string response)
     */
    static public function ping($server,$from,$to){
        return PicoraXMLRPC::call($server,'pingback.ping',$from,$to);
    }
    /**
     * Scrapes a given URL for links and sends PingBack pings from that URL to each of the links found.
     * @param string $from URL to scan
     * @param string $text Manually specify the page contents of the $from URL
     * @return array of array(bool success,string response) for each ping sent
     */
    static public function autoPing($from,$text = false){
        if(!$text && !($text = self::getURL($from)))
            return false;
        return self::autoPingCallback($from,$text);
    }
    static protected function autoPingCallback($from,$text){
        $links = self::scrape($text);
        $response = array();
        foreach($links as $link)
            $response[] = (($server = self::discover($link)))
                ? self::ping($server,$from,$link)
                : array(false,'Could not autodiscover server from "'.$link.'"')
            ;    
        return $response;
    }
    static protected function getURL($url,$headers = false,$limit = false,$timeout = 30){
        $url_parsed = parse_url($url);
        $host = (isset($url_parsed["host"])) ? $url_parsed["host"] : '';
        $port = (isset($url_parsed["port"])) ? $url_parsed["port"] : 80;
        if($port == 0)
            $port = 80;
        $path = $url_parsed["path"];
        if(isset($url_parsed["query"]) && $url_parsed["query"] != "")
            $path .= "?".$url_parsed["query"];
        $out = "GET $path HTTP/1.0\r\nHost: $host\r\n\r\n";
        $fp = @fsockopen($host,$port,$errno,$errstr,$timeout);
        if(!$fp)
            return false;
        fwrite($fp,$out);
        $body = false;
        $out = '';
        $headers = '';
        while(!feof($fp)){
            $s = fgets($fp,1024);
            if($body)
                $out .= $s;
            if($s == "\r\n"){
                if($headers){
                    $response = $headers.($limit ? fgets($fp,$limit) : '');
                    fclose($fp);
                    return $response;
                }
                $body = true;
            }
        }
        fclose($fp);
        return $out;
    }
    static protected function scrape($str){
        preg_match_all("/href=('http:\/\/.+?'|\"http:\/\/.+?\"|http:\/\/.+?)[\s>]/",$str,$matches,PREG_PATTERN_ORDER);
        return array_map(array('PicoraPingBack','arrayMapCallback'),$matches[1]); 
    }
    static protected function arrayMapCallback($str){
        return html_entity_decode(trim($str," \"'"));
    }
}