<?php
/*
 * Copyright (c) 2015 Aimy Extensions, Lingua-Systems Software GmbH
 *
 * http://www.aimy-extensions.com/
 *
 * License: GNU GPLv2, see LICENSE.txt within distribution and/or
 *          http://www.aimy-extensions.com/software-license.html
 */
 defined( '_JEXEC' ) or die(); require_once( JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_aimysitemap' . DIRECTORY_SEPARATOR . 'Uri.php' ); abstract class AimySitemapHttpClient { static private $socket_errstr = null; static private $name = 'AimySitemapCrawler/3.15.1'; static private $ua = 'Mozilla/5.0 (compatible; %s)'; const MSG_PARSE_HTTP = 255; const MSG_SOCKET = 256; static public function head_url( &$uo, $timeout = 10 ) { $resp = self::http_sndrcv( $uo, 'HEAD ' . $uo->getResourceHTTP() . ' HTTP/1.0', $timeout ); return array( 'head' => self::parse_head( $resp ) ); } static public function get_url( &$uo, $timeout = 10 ) { $data = self::http_sndrcv( $uo, 'GET ' . $uo->getResourceHTTP() . ' HTTP/1.0', $timeout ); list( $head, $body ) = explode( "\r\n\r\n", $data, 2 ); return array( 'head' => self::parse_head( $head ), 'body' => $body ); } static public function php_supports_ssl() { $tls = stream_get_transports(); return in_array( 'ssl', $tls ); } static private function http_sndrcv( &$uo, $q, $timeout = 10 ) { $host = $uo->getHost(); $port = $uo->getPort() ? $uo->getPort() : 80; $proto = $uo->getScheme() ? strtolower( $uo->getScheme() ) : 'http'; $trans = ''; $ctx_opt = array(); $ctx = stream_context_create( $ctx_opt ); set_error_handler( 'self::socket_error_handler' ); $fp = stream_socket_client( "$trans$host:$port", $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $ctx ); restore_error_handler(); if ( $fp === false or ! empty( $errstr ) ) { if ( empty( $errstr ) ) { $errstr = self::$socket_errstr; self::$socket_errstr = null; } throw new RuntimeException( "Failed to open connection: $errstr", self::MSG_SOCKET ); } fwrite( $fp, $q . "\r\n" . 'Host: ' . $host . "\r\n" . 'User-Agent: ' . self::get_ua() . "\r\n" . 'Accept: ' . '*/*' . "\r\n" . 'Connection: ' . 'close' . "\r\n" . "\r\n" ); fflush( $fp ); $buf = ''; while ( ! feof( $fp ) ) { $buf .= fgets( $fp, 1024 ); } fclose( $fp ); return $buf; } static public function get_ua() { return sprintf( self::$ua, self::$name ); } static public function set_ua_name( $n ) { self::$name = trim( $n ); } static private function parse_head( $s ) { $a = explode( "\r\n", trim( $s ) ); $h = array_shift( $a ); $r = array(); preg_match( '#^HTTP/1.\d (\d{3}) #', $h, $m ); if ( count( $m ) != 2 ) { AimySitemapLogger::debug( "Crawl: HTTP HEAD response: [$s]" ); AimySitemapLogger::debug( "Crawl: parse_head failed: [$h]" ); throw new RuntimeException( 'Failed to parse head: status code not found', self::MSG_PARSE_HTTP ); } $r[ 'code' ] = $m[ 1 ]; while ( ! empty( $a ) ) { $l = array_pop( $a ); $p = explode( ':', $l, 2 ); if ( count( $p ) != 2 ) { throw new RuntimeException( 'Failed to parse head: failed to split fields', self::MSG_PARSE_HTTP ); } $r[ $p[0] ] = trim( $p[1] ); } return $r; } static private function socket_error_handler( $code, $text, $f, $l ) { self::$socket_errstr = $text; } } 
