MediaWiki  REL1_19
SquidUpdate.php
Go to the documentation of this file.
00001 <?php
00012 class SquidUpdate {
00013         var $urlArr, $mMaxTitles;
00014 
00015         function __construct( $urlArr = Array(), $maxTitles = false ) {
00016                 global $wgMaxSquidPurgeTitles;
00017                 if ( $maxTitles === false ) {
00018                         $this->mMaxTitles = $wgMaxSquidPurgeTitles;
00019                 } else {
00020                         $this->mMaxTitles = $maxTitles;
00021                 }
00022                 if ( count( $urlArr ) > $this->mMaxTitles ) {
00023                         $urlArr = array_slice( $urlArr, 0, $this->mMaxTitles );
00024                 }
00025                 $this->urlArr = $urlArr;
00026         }
00027 
00033         static function newFromLinksTo( &$title ) {
00034                 global $wgMaxSquidPurgeTitles;
00035                 wfProfileIn( __METHOD__ );
00036 
00037                 # Get a list of URLs linking to this page
00038                 $dbr = wfGetDB( DB_SLAVE );
00039                 $res = $dbr->select( array( 'links', 'page' ),
00040                         array( 'page_namespace', 'page_title' ),
00041                         array(
00042                                 'pl_namespace' => $title->getNamespace(),
00043                                 'pl_title'     => $title->getDBkey(),
00044                                 'pl_from=page_id' ),
00045                         __METHOD__ );
00046                 $blurlArr = $title->getSquidURLs();
00047                 if ( $dbr->numRows( $res ) <= $wgMaxSquidPurgeTitles ) {
00048                         foreach ( $res as $BL ) {
00049                                 $tobj = Title::makeTitle( $BL->page_namespace, $BL->page_title ) ;
00050                                 $blurlArr[] = $tobj->getInternalURL();
00051                         }
00052                 }
00053 
00054                 wfProfileOut( __METHOD__ );
00055                 return new SquidUpdate( $blurlArr );
00056         }
00057 
00066         static function newFromTitles( $titles, $urlArr = array() ) {
00067                 global $wgMaxSquidPurgeTitles;
00068                 $i = 0;
00069                 foreach ( $titles as $title ) {
00070                         $urlArr[] = $title->getInternalURL();
00071                         if ( $i++ > $wgMaxSquidPurgeTitles ) {
00072                                 break;
00073                         }
00074                 }
00075                 return new SquidUpdate( $urlArr );
00076         }
00077 
00083         static function newSimplePurge( &$title ) {
00084                 $urlArr = $title->getSquidURLs();
00085                 return new SquidUpdate( $urlArr );
00086         }
00087 
00091         function doUpdate() {
00092                 SquidUpdate::purge( $this->urlArr );
00093         }
00094 
00104         static function purge( $urlArr ) {
00105                 global $wgSquidServers, $wgHTCPMulticastAddress, $wgHTCPPort;
00106 
00107                 /*if ( (@$wgSquidServers[0]) == 'echo' ) {
00108                         echo implode("<br />\n", $urlArr) . "<br />\n";
00109                         return;
00110                 }*/
00111 
00112                 if( !$urlArr ) {
00113                         return;
00114                 }
00115 
00116                 if ( $wgHTCPMulticastAddress && $wgHTCPPort ) {
00117                         SquidUpdate::HTCPPurge( $urlArr );
00118                 }
00119 
00120                 wfProfileIn( __METHOD__ );
00121 
00122                 $maxSocketsPerSquid = 8; //  socket cap per Squid
00123                 $urlsPerSocket = 400; // 400 seems to be a good tradeoff, opening a socket takes a while
00124                 $socketsPerSquid = ceil( count( $urlArr ) / $urlsPerSocket );
00125                 if ( $socketsPerSquid > $maxSocketsPerSquid ) {
00126                         $socketsPerSquid = $maxSocketsPerSquid;
00127                 }
00128 
00129                 $pool = new SquidPurgeClientPool;
00130                 $chunks = array_chunk( $urlArr, ceil( count( $urlArr ) / $socketsPerSquid ) );
00131                 foreach ( $wgSquidServers as $server ) {
00132                         foreach ( $chunks as $chunk ) {
00133                                 $client = new SquidPurgeClient( $server );
00134                                 foreach ( $chunk as $url ) {
00135                                         $client->queuePurge( $url );
00136                                 }
00137                                 $pool->addClient( $client );
00138                         }
00139                 }
00140                 $pool->run();
00141 
00142                 wfProfileOut( __METHOD__ );
00143         }
00144 
00149         static function HTCPPurge( $urlArr ) {
00150                 global $wgHTCPMulticastAddress, $wgHTCPMulticastTTL, $wgHTCPPort;
00151                 wfProfileIn( __METHOD__ );
00152 
00153                 $htcpOpCLR = 4; // HTCP CLR
00154 
00155                 // @todo FIXME: PHP doesn't support these socket constants (include/linux/in.h)
00156                 if( !defined( "IPPROTO_IP" ) ) {
00157                         define( "IPPROTO_IP", 0 );
00158                         define( "IP_MULTICAST_LOOP", 34 );
00159                         define( "IP_MULTICAST_TTL", 33 );
00160                 }
00161 
00162                 // pfsockopen doesn't work because we need set_sock_opt
00163                 $conn = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );
00164                 if ( $conn ) {
00165                         // Set socket options
00166                         socket_set_option( $conn, IPPROTO_IP, IP_MULTICAST_LOOP, 0 );
00167                         if ( $wgHTCPMulticastTTL != 1 )
00168                                 socket_set_option( $conn, IPPROTO_IP, IP_MULTICAST_TTL,
00169                                         $wgHTCPMulticastTTL );
00170 
00171                         foreach ( $urlArr as $url ) {
00172                                 if( !is_string( $url ) ) {
00173                                         throw new MWException( 'Bad purge URL' );
00174                                 }
00175                                 $url = SquidUpdate::expand( $url );
00176 
00177                                 // Construct a minimal HTCP request diagram
00178                                 // as per RFC 2756
00179                                 // Opcode 'CLR', no response desired, no auth
00180                                 $htcpTransID = rand();
00181 
00182                                 $htcpSpecifier = pack( 'na4na*na8n',
00183                                         4, 'HEAD', strlen( $url ), $url,
00184                                         8, 'HTTP/1.0', 0 );
00185 
00186                                 $htcpDataLen = 8 + 2 + strlen( $htcpSpecifier );
00187                                 $htcpLen = 4 + $htcpDataLen + 2;
00188 
00189                                 // Note! Squid gets the bit order of the first
00190                                 // word wrong, wrt the RFC. Apparently no other
00191                                 // implementation exists, so adapt to Squid
00192                                 $htcpPacket = pack( 'nxxnCxNxxa*n',
00193                                         $htcpLen, $htcpDataLen, $htcpOpCLR,
00194                                         $htcpTransID, $htcpSpecifier, 2);
00195 
00196                                 // Send out
00197                                 wfDebug( "Purging URL $url via HTCP\n" );
00198                                 socket_sendto( $conn, $htcpPacket, $htcpLen, 0,
00199                                         $wgHTCPMulticastAddress, $wgHTCPPort );
00200                         }
00201                 } else {
00202                         $errstr = socket_strerror( socket_last_error() );
00203                         wfDebug( __METHOD__ . "(): Error opening UDP socket: $errstr\n" );
00204                 }
00205                 wfProfileOut( __METHOD__ );
00206         }
00207 
00223         static function expand( $url ) {
00224                 return wfExpandUrl( $url, PROTO_INTERNAL );
00225         }
00226 }