2009-12-02 18:32:20 +01:00
< ? php
require_once 'ykval-config.php' ;
require_once 'ykval-common.php' ;
2009-12-15 16:39:47 +01:00
require_once 'ykval-db.php' ;
2009-12-02 18:32:20 +01:00
class SyncLib
{
public $syncServers = null ;
public $dbConn = null ;
2009-12-15 11:17:51 +01:00
function __construct ( $logname = 'ykval-synclib' )
2009-12-02 18:32:20 +01:00
{
2009-12-15 11:17:51 +01:00
$this -> logname = $logname ;
2009-12-02 18:32:20 +01:00
global $baseParams ;
2010-01-08 17:35:25 +01:00
$this -> syncServers = $baseParams [ '__YKVAL_SYNC_POOL__' ];
$this -> db = new Db ( $baseParams [ '__YKVAL_DB_DSN__' ],
2009-12-02 18:32:20 +01:00
$baseParams [ '__YKVAL_DB_USER__' ],
$baseParams [ '__YKVAL_DB_PW__' ],
2010-01-08 17:35:25 +01:00
$baseParams [ '__YKVAL_DB_OPTIONS__' ]);
2009-12-15 11:17:51 +01:00
$this -> isConnected = $this -> db -> connect ();
2009-12-02 18:32:20 +01:00
$this -> random_key = rand ( 0 , 1 << 16 );
2009-12-07 16:31:33 +01:00
$this -> max_url_chunk = $baseParams [ '__YKVAL_SYNC_MAX_SIMUL__' ];
2009-12-07 20:13:20 +01:00
$this -> resync_timeout = $baseParams [ '__YKVAL_SYNC_RESYNC_TIMEOUT__' ];
2009-12-07 14:33:24 +01:00
2009-12-02 18:32:20 +01:00
}
2009-12-15 11:17:51 +01:00
2009-12-02 18:32:20 +01:00
2009-12-15 11:17:51 +01:00
function isConnected ()
{
return $this -> isConnected ;
}
2009-12-02 18:32:20 +01:00
function DbTimeToUnix ( $db_time )
{
$unix = strptime ( $db_time , '%F %H:%M:%S' );
return mktime ( $unix [ tm_hour ], $unix [ tm_min ], $unix [ tm_sec ], $unix [ tm_mon ] + 1 , $unix [ tm_mday ], $unix [ tm_year ] + 1900 );
}
function UnixToDbTime ( $unix )
{
return date ( 'Y-m-d H:i:s' , $unix );
}
function getServer ( $index )
{
if ( isset ( $this -> syncServers [ $index ])) return $this -> syncServers [ $index ];
else return " " ;
}
2009-12-15 11:17:51 +01:00
function getClientData ( $client )
{
2010-01-08 17:35:25 +01:00
$res = $this -> db -> customQuery ( " SELECT id, secret FROM clients WHERE active AND id=' " . $client . " ' " );
if ( $res -> rowCount () > 0 ) return $res -> fetch ( PDO :: FETCH_ASSOC );
else return false ;
2009-12-15 11:17:51 +01:00
}
2009-12-02 18:32:20 +01:00
function getLast ()
{
$res = $this -> db -> last ( 'queue' , 1 );
2009-12-07 17:10:07 +01:00
$info = $this -> otpParamsFromInfoString ( $res [ 'info' ]);
2010-01-08 14:54:33 +01:00
return array ( 'queued' => $res [ 'queued' ],
'modified' => $res [ 'modified' ],
2009-12-02 18:32:20 +01:00
'otp' => $res [ 'otp' ],
2009-12-15 11:17:51 +01:00
'server' => $res [ 'server' ],
'nonce' => $info [ 'nonce' ],
2010-01-08 14:54:33 +01:00
'yk_publicname' => $info [ 'yk_publicname' ],
2009-12-02 18:32:20 +01:00
'yk_counter' => $info [ 'yk_counter' ],
'yk_use' => $info [ 'yk_use' ],
'yk_high' => $info [ 'yk_high' ],
'yk_low' => $info [ 'yk_low' ]);
}
public function getQueueLength ()
{
2010-01-08 14:54:33 +01:00
return count ( $this -> db -> last ( 'queue' , null ));
2009-12-02 18:32:20 +01:00
}
2009-12-07 14:33:24 +01:00
public function createInfoString ( $otpParams , $localParams )
2009-12-02 18:32:20 +01:00
{
2010-01-08 14:54:33 +01:00
return 'yk_publicname=' . $otpParams [ 'yk_publicname' ] .
2009-12-04 12:57:49 +01:00
'&yk_counter=' . $otpParams [ 'yk_counter' ] .
'&yk_use=' . $otpParams [ 'yk_use' ] .
'&yk_high=' . $otpParams [ 'yk_high' ] .
2009-12-07 14:33:24 +01:00
'&yk_low=' . $otpParams [ 'yk_low' ] .
2009-12-15 11:17:51 +01:00
'&nonce=' . $otpParams [ 'nonce' ] .
2009-12-07 14:33:24 +01:00
',local_counter=' . $localParams [ 'yk_counter' ] .
'&local_use=' . $localParams [ 'yk_use' ];
}
2009-12-07 17:10:07 +01:00
public function otpParamsFromInfoString ( $info ) {
$out = explode ( " , " , $info );
parse_str ( $out [ 0 ], $params );
return $params ;
}
2009-12-07 14:33:24 +01:00
public function otpPartFromInfoString ( $info ) {
$out = explode ( " , " , $info );
return $out [ 0 ];
}
2009-12-07 17:10:07 +01:00
public function localParamsFromInfoString ( $info )
2009-12-07 14:33:24 +01:00
{
$out = explode ( " , " , $info );
2009-12-07 17:10:07 +01:00
parse_str ( $out [ 1 ], $params );
return array ( 'yk_counter' => $params [ 'local_counter' ],
'yk_use' => $params [ 'local_use' ]);
2009-12-07 14:33:24 +01:00
}
public function queue ( $otpParams , $localParams )
{
$info = $this -> createInfoString ( $otpParams , $localParams );
2009-12-04 12:57:49 +01:00
$this -> otpParams = $otpParams ;
$this -> localParams = $localParams ;
2010-01-08 14:54:33 +01:00
$queued = time ();
2009-12-02 18:32:20 +01:00
$res = True ;
foreach ( $this -> syncServers as $server ) {
2010-01-08 14:54:33 +01:00
if ( ! $this -> db -> save ( 'queue' , array ( 'queued' => $queued ,
'modified' => $otpParams [ 'modified' ],
2009-12-04 12:57:49 +01:00
'otp' => $otpParams [ 'otp' ],
2009-12-02 18:32:20 +01:00
'server' => $server ,
'random_key' => $this -> random_key ,
'info' => $info ))) $res = False ;
}
return $res ;
}
public function getNumberOfServers ()
{
if ( is_array ( $this -> syncServers )) return count ( $this -> syncServers );
else return 0 ;
}
2009-12-15 11:17:51 +01:00
public function log ( $level , $msg , $params = NULL )
2009-12-02 18:32:20 +01:00
{
2009-12-15 11:17:51 +01:00
$logMsg = $this -> logname . ':' . $level . ':' . $msg ;
if ( $params ) $logMsg .= ' modified=' . $params [ 'modified' ] .
' nonce=' . $params [ 'nonce' ] .
2010-01-08 14:54:33 +01:00
' yk_publicname=' . $params [ 'yk_publicname' ] .
2009-12-15 11:17:51 +01:00
' yk_counter=' . $params [ 'yk_counter' ] .
' yk_use=' . $params [ 'yk_use' ] .
' yk_high=' . $params [ 'yk_high' ] .
' yk_low=' . $params [ 'yk_low' ];
2009-12-02 18:32:20 +01:00
error_log ( $logMsg );
}
2010-01-08 14:54:33 +01:00
function getLocalParams ( $yk_publicname )
2009-12-15 11:17:51 +01:00
{
2010-01-08 14:54:33 +01:00
$this -> log ( " notice " , " searching for " . $yk_publicname . " ( " . $yk_publicname . " ) in local db " );
$res = $this -> db -> findBy ( 'yubikeys' , 'yk_publicname' , $yk_publicname , 1 );
2009-12-02 18:32:20 +01:00
2009-12-15 11:17:51 +01:00
if ( ! $res ) {
2010-01-08 14:54:33 +01:00
$this -> log ( 'notice' , 'Discovered new identity ' . $yk_publicname );
$this -> db -> save ( 'yubikeys' , array ( 'yk_publicname' => $yk_publicname ,
2009-12-15 11:17:51 +01:00
'active' => 1 ,
2010-01-08 14:54:33 +01:00
'yk_counter' => 0 ,
'yk_use' => 0 ,
2009-12-15 11:17:51 +01:00
'nonce' => 0 ));
2010-01-08 14:54:33 +01:00
$res = $this -> db -> findBy ( 'yubikeys' , 'yk_publicname' , $yk_publicname , 1 );
2009-12-15 11:17:51 +01:00
}
if ( $res ) {
$localParams = array ( 'id' => $res [ 'id' ],
2010-01-08 14:54:33 +01:00
'modified' => $res [ 'modified' ],
2009-12-15 11:17:51 +01:00
'otp' => $res [ 'otp' ],
'nonce' => $res [ 'nonce' ],
'active' => $res [ 'active' ],
2010-01-08 14:54:33 +01:00
'yk_publicname' => $yk_publicname ,
'yk_counter' => $res [ 'yk_counter' ],
'yk_use' => $res [ 'yk_use' ],
'yk_high' => $res [ 'yk_high' ],
'yk_low' => $res [ 'yk_low' ]);
2009-12-15 11:17:51 +01:00
$this -> log ( " notice " , " counter found in db " , $localParams );
return $localParams ;
} else {
2010-01-08 14:54:33 +01:00
$this -> log ( 'notice' , 'params for identity ' . $yk_publicname . ' not found in database' );
2009-12-15 11:17:51 +01:00
return false ;
}
2009-12-02 18:32:20 +01:00
}
private function parseParamsFromMultiLineString ( $str )
{
preg_match ( " /^modified=([0-9]*)/m " , $str , $out );
$resParams [ 'modified' ] = $out [ 1 ];
2010-01-08 14:54:33 +01:00
preg_match ( " /^yk_publicname=([[:alpha:]]*)/m " , $str , $out );
$resParams [ 'yk_publicname' ] = $out [ 1 ];
2009-12-02 18:32:20 +01:00
preg_match ( " /^yk_counter=([0-9]*)/m " , $str , $out );
$resParams [ 'yk_counter' ] = $out [ 1 ];
preg_match ( " /^yk_use=([0-9]*)/m " , $str , $out );
$resParams [ 'yk_use' ] = $out [ 1 ];
preg_match ( " /^yk_high=([0-9]*)/m " , $str , $out );
$resParams [ 'yk_high' ] = $out [ 1 ];
preg_match ( " /^yk_low=([0-9]*)/m " , $str , $out );
$resParams [ 'yk_low' ] = $out [ 1 ];
2009-12-15 12:32:28 +01:00
preg_match ( " /^nonce=([[:alnum:]]*)/m " , $str , $out );
2009-12-15 11:17:51 +01:00
$resParams [ 'nonce' ] = $out [ 1 ];
2009-12-02 18:32:20 +01:00
return $resParams ;
}
public function updateDbCounters ( $params )
{
2010-01-08 14:54:33 +01:00
$res = $this -> db -> lastBy ( 'yubikeys' , 'yk_publicname' , $params [ 'yk_publicname' ]);
2009-12-02 18:32:20 +01:00
if ( isset ( $res [ 'id' ])) {
2010-01-08 14:54:33 +01:00
$condition = '(' . $params [ 'yk_counter' ] . '>yk_counter or (' . $params [ 'yk_counter' ] . '=yk_counter and ' .
$params [ 'yk_use' ] . '>yk_use))' ;
2009-12-07 18:21:38 +01:00
if ( ! $this -> db -> conditional_update ( 'yubikeys' ,
$res [ 'id' ],
2010-01-08 14:54:33 +01:00
array ( 'modified' => $params [ 'modified' ],
'yk_counter' => $params [ 'yk_counter' ],
'yk_use' => $params [ 'yk_use' ],
'yk_low' => $params [ 'yk_low' ],
'yk_high' => $params [ 'yk_high' ],
2009-12-15 11:17:51 +01:00
'nonce' => $params [ 'nonce' ]),
2009-12-07 18:21:38 +01:00
$condition ))
2009-12-02 18:32:20 +01:00
{
error_log ( " ykval-synclib:critical: failed to update internal DB with new counters " );
return false ;
} else {
2009-12-07 18:21:38 +01:00
if ( mysql_affected_rows () > 0 ) $this -> log ( " notice " , " updated database " , $params );
else $this -> log ( 'notice' , 'database not updated' , $params );
2009-12-02 18:32:20 +01:00
return true ;
}
} else return false ;
}
2009-12-07 18:21:38 +01:00
2009-12-02 18:32:20 +01:00
public function countersHigherThan ( $p1 , $p2 )
{
if ( $p1 [ 'yk_counter' ] > $p2 [ 'yk_counter' ] ||
( $p1 [ 'yk_counter' ] == $p2 [ 'yk_counter' ] &&
$p1 [ 'yk_use' ] > $p2 [ 'yk_use' ])) return true ;
else return false ;
}
public function countersHigherThanOrEqual ( $p1 , $p2 )
{
if ( $p1 [ 'yk_counter' ] > $p2 [ 'yk_counter' ] ||
( $p1 [ 'yk_counter' ] == $p2 [ 'yk_counter' ] &&
$p1 [ 'yk_use' ] >= $p2 [ 'yk_use' ])) return true ;
else return false ;
}
2009-12-15 11:17:51 +01:00
public function countersEqual ( $p1 , $p2 ) {
return ( $p1 [ 'yk_counter' ] == $p2 [ 'yk_counter' ]) && ( $p1 [ 'yk_use' ] == $p2 [ 'yk_use' ]);
}
2009-12-07 14:33:24 +01:00
public function deleteQueueEntry ( $answer )
{
preg_match ( '/url=(.*)\?/' , $answer , $out );
$server = $out [ 1 ];
debug ( " server= " . $server );
2010-01-08 14:54:33 +01:00
$this -> db -> deleteByMultiple ( 'queue' ,
array ( " modified " => $this -> otpParams [ 'modified' ],
" random_key " => $this -> random_key ,
'server' => $server ));
2009-12-07 14:33:24 +01:00
}
2010-01-08 14:54:33 +01:00
public function reSync ( $older_than = 10 , $timeout )
2009-12-07 14:33:24 +01:00
{
2010-01-08 14:54:33 +01:00
/* Loop over all unique servers in queue */
$res = $this -> db -> customQuery ( " select distinct server from queue WHERE (queued_time < DATE_SUB(now(), INTERVAL " . $older_than . " MINUTE) or queued_time is null) " );
error_log ( " found " . mysql_num_rows ( $res ) . " unique servers " );
return true ;
2009-12-07 14:33:24 +01:00
$urls = array ();
# TODO: move statement to DB class, this looks grotesque
2010-01-08 14:54:33 +01:00
$res = $this -> db -> customQuery ( " select * from queue WHERE (queued_time < DATE_SUB(now(), INTERVAL " . $older_than . " MINUTE) or queued_time is null) and server=' " . $server . " ' " );
2009-12-07 14:40:57 +01:00
$this -> log ( 'notice' , " found " . mysql_num_rows ( $res ) . " old queue entries " );
2009-12-07 14:33:24 +01:00
$collection = array ();
while ( $row = mysql_fetch_array ( $res , MYSQL_ASSOC )) {
$collection [] = $row ;
}
foreach ( $collection as $row ) {
2009-12-07 14:42:09 +01:00
$this -> log ( 'notice' , " server= " . $row [ 'server' ] . " , info= " . $row [ 'info' ]);
2009-12-07 14:33:24 +01:00
$urls [] = $row [ 'server' ] .
" ?otp= " . $row [ 'otp' ] .
2010-01-08 14:54:33 +01:00
" &modified= " . $row [ 'modified' ] .
2009-12-07 14:33:24 +01:00
" & " . $this -> otpPartFromInfoString ( $row [ 'info' ]);
}
2010-01-08 14:54:33 +01:00
/* Send out until no URL's left, or a timeout */
foreach ( $urls as $url ) {
2009-12-07 14:33:24 +01:00
2010-01-08 14:54:33 +01:00
$ch = curl_init ( $this -> url );
curl_setopt ( $ch , CURLOPT_USERAGENT , " YK-VAL " );
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , 1 );
curl_setopt ( $ch , CURLOPT_SSL_VERIFYPEER , 0 );
curl_setopt ( $ch , CURLOPT_FAILONERROR , true );
curl_setopt ( $ch , CURLOPT_TIMEOUT , $timeout );
$response = curl_exec ( $ch );
curl_close ( $ch );
if ( $response == False ) {
$this -> log ( 'warning' , 'Timeout. Stopping queue resync at the moment' );
return false ;
2009-12-07 14:33:24 +01:00
}
2010-01-08 14:54:33 +01:00
if ( preg_match ( " /^OK/ " , $respone )) {
$resParams = $this -> parseParamsFromMultiLineString ( $response );
2009-12-07 14:33:24 +01:00
$this -> log ( " notice " , " response contains " , $resParams );
/* Update database counters */
$this -> updateDbCounters ( $resParams );
/* Warnings and deletion */
preg_match ( " /url=(.*) \ ?.*otp=([[:alpha:]]*)/ " , $answer , $out );
$server = $out [ 1 ];
$otp = $out [ 2 ];
$this -> log ( 'notice' , 'Searching for entry with' .
' server=' . $server .
' otp=' . $otp );
$entries = $this -> db -> findByMultiple ( 'queue' ,
array ( 'server' => $server ,
'otp' => $otp ));
$this -> log ( 'notice' , 'found ' . count ( $entries ) . ' entries' );
if ( count ( $entries ) > 1 ) $this -> log ( 'warning' , 'Multiple queue entries with the same OTP. We could have an OTP replay attempt in the system' );
foreach ( $entries as $entry ) {
/* Warnings */
2009-12-07 17:10:07 +01:00
$localParams = $this -> localParamsFromInfoString ( $entry [ 'info' ]);
$otpParams = $this -> otpParamsFromInfoString ( $entry [ 'info' ]);
2009-12-07 14:33:24 +01:00
/* Check for warnings
If received sync response have lower counters than locally saved
last counters ( indicating that remote server wasn ' t synced )
*/
if ( $this -> countersHigherThan ( $localParams , $resParams )) {
$this -> log ( " warning " , " queued:Remote server out of sync, local counters " , $localParams );
$this -> log ( " warning " , " queued:Remote server out of sync, remote counters " , $resParams );
}
/* If received sync response have higher counters than locally saved
last counters ( indicating that local server wasn ' t synced )
*/
if ( $this -> countersHigherThan ( $resParams , $localParams )) {
$this -> log ( " warning " , " queued:Local server out of sync, local counters " , $localParams );
$this -> log ( " warning " , " queued:Local server out of sync, remote counters " , $resParams );
}
2010-01-08 14:54:33 +01:00
2009-12-15 11:17:51 +01:00
if ( $this -> countersHigherThan ( $resParams , $otpParams ) ||
( $this -> countersEqual ( $resParams , $otpParams ) &&
$resParams [ 'nonce' ] != $otpParams [ 'nonce' ])) {
/* If received sync response have higher counters than OTP or same counters with different nonce
( indicating REPLAYED_OTP )
*/
2010-01-08 14:54:33 +01:00
2009-12-07 14:33:24 +01:00
$this -> log ( " warning " , " queued:replayed OTP, remote counters " , $resParams );
$this -> log ( " warning " , " queued:replayed OTP, otp counters " , $otpParams );
}
/* Deletion */
$this -> log ( 'notice' , 'deleting queue entry with id=' . $entry [ 'id' ]);
$this -> db -> deleteByMultiple ( 'queue' , array ( 'id' => $entry [ 'id' ]));
}
}
}
2010-01-08 14:54:33 +01:00
return true ;
2009-12-07 14:33:24 +01:00
}
2009-12-07 20:13:20 +01:00
public function sync ( $ans_req , $timeout = 1 )
2009-12-02 18:32:20 +01:00
{
2009-12-04 11:58:37 +01:00
/*
Construct URLs
*/
2009-12-02 18:32:20 +01:00
$urls = array ();
2010-01-08 14:54:33 +01:00
$res = $this -> db -> findByMultiple ( 'queue' , array ( " modified " => $this -> otpParams [ 'modified' ], " random_key " => $this -> random_key ));
2009-12-02 18:32:20 +01:00
foreach ( $res as $row ) {
2009-12-04 11:58:37 +01:00
$urls [] = $row [ 'server' ] .
" ?otp= " . $row [ 'otp' ] .
2010-01-08 14:54:33 +01:00
" &modified= " . $row [ 'modified' ] .
2009-12-07 14:33:24 +01:00
" & " . $this -> otpPartFromInfoString ( $row [ 'info' ]);
2009-12-02 18:32:20 +01:00
}
2009-12-04 11:58:37 +01:00
/*
Send out requests
*/
2009-12-08 17:07:08 +01:00
$ans_arr = $this -> retrieveURLasync ( $urls , $ans_req , $timeout );
2009-12-02 18:32:20 +01:00
if ( ! is_array ( $ans_arr )) {
$this -> log ( 'warning' , 'No responses from validation server pool' );
$ans_arr = array ();
}
2009-12-04 11:58:37 +01:00
/*
Parse responses
*/
2009-12-04 12:57:49 +01:00
$localParams = $this -> localParams ;
2009-12-02 18:32:20 +01:00
$this -> answers = count ( $ans_arr );
$this -> valid_answers = 0 ;
foreach ( $ans_arr as $answer ){
2009-12-04 11:58:37 +01:00
/* Parse out parameters from each response */
2009-12-02 18:32:20 +01:00
$resParams = $this -> parseParamsFromMultiLineString ( $answer );
$this -> log ( " notice " , " local db contains " , $localParams );
$this -> log ( " notice " , " response contains " , $resParams );
2009-12-07 18:21:38 +01:00
/* Update internal DB (conditional) */
$this -> updateDbCounters ( $resParams );
2009-12-02 18:32:20 +01:00
2009-12-04 11:58:37 +01:00
/* Check for warnings
2009-12-15 11:17:51 +01:00
If received sync response have lower counters than local db
( indicating that remote server wasn ' t synced )
2009-12-04 11:58:37 +01:00
*/
2009-12-02 18:32:20 +01:00
if ( $this -> countersHigherThan ( $localParams , $resParams )) {
$this -> log ( " warning " , " Remote server out of sync, local counters " , $localParams );
$this -> log ( " warning " , " Remote server out of sync, remote counters " , $resParams );
}
2009-12-15 11:17:51 +01:00
/* If received sync response have higher counters than local db
( indicating that local server wasn ' t synced )
2009-12-04 11:58:37 +01:00
*/
2009-12-02 18:32:20 +01:00
if ( $this -> countersHigherThan ( $resParams , $localParams )) {
$this -> log ( " warning " , " Local server out of sync, local counters " , $localParams );
$this -> log ( " warning " , " Local server out of sync, remote counters " , $resParams );
}
2009-12-15 11:17:51 +01:00
if ( $this -> countersHigherThan ( $resParams , $this -> otpParams ) ||
( $this -> countersEqual ( $resParams , $this -> otpParams ) &&
$resParams [ 'nonce' ] != $this -> otpParams [ 'nonce' ])) {
/* If received sync response have higher counters than OTP or same counters with different nonce
( indicating REPLAYED_OTP )
*/
2009-12-02 18:32:20 +01:00
$this -> log ( " warning " , " replayed OTP, remote counters " , $resParams );
$this -> log ( " warning " , " replayed OTP, otp counters " , $this -> otpParams );
2009-12-15 11:17:51 +01:00
} else {
/* The answer is ok since a REPLAY was not indicated */
$this -> valid_answers ++ ;
2009-12-02 18:32:20 +01:00
}
2009-12-15 11:17:51 +01:00
2009-12-02 18:32:20 +01:00
2009-12-04 11:58:37 +01:00
/* Delete entry from table */
2009-12-07 14:33:24 +01:00
$this -> deleteQueueEntry ( $answer );
2009-12-02 18:32:20 +01:00
}
2010-01-08 14:54:33 +01:00
/*
NULL queued_time for remaining entries in queue , to allow
daemon to take care of them as soon as possible . */
$this -> db -> updateBy ( 'queue' , 'random_key' , $this -> random_key ,
array ( 'queued' => NULL ));
2009-12-04 11:58:37 +01:00
/* Return true if valid answers equals required answers .
Since we only obtain the required amount of answers from
retrieveAsync this indicates that all answers were actually valid .
2009-12-02 18:32:20 +01:00
Otherwise , return false . */
if ( $this -> valid_answers == $ans_req ) return True ;
else return False ;
}
public function getNumberOfValidAnswers ()
{
if ( isset ( $this -> valid_answers )) return $this -> valid_answers ;
else return 0 ;
}
public function getNumberOfAnswers ()
{
if ( isset ( $this -> answers )) return $this -> answers ;
else return 0 ;
}
2009-12-04 11:58:37 +01:00
/*
This function takes a list of URLs . It will return the content of
the first successfully retrieved URL , whose content matches ^ OK .
The request are sent asynchronously . Some of the URLs can fail
with unknown host , connection errors , or network timeout , but as
long as one of the URLs given work , data will be returned . If all
URLs fail , data from some URL that did not match parameter $match
( defaults to ^ OK ) is returned , or if all URLs failed , false .
*/
2009-12-07 16:31:33 +01:00
function retrieveURLasync ( $urls , $ans_req = 1 , $timeout = 1.0 ) {
2009-12-04 11:58:37 +01:00
$mh = curl_multi_init ();
$ch = array ();
foreach ( $urls as $id => $url ) {
2010-01-08 17:35:25 +01:00
error_log ( " url is " . $url );
2009-12-04 11:58:37 +01:00
$handle = curl_init ();
curl_setopt ( $handle , CURLOPT_URL , $url );
curl_setopt ( $handle , CURLOPT_USERAGENT , " YK-VAL " );
curl_setopt ( $handle , CURLOPT_RETURNTRANSFER , 1 );
curl_setopt ( $handle , CURLOPT_FAILONERROR , true );
2009-12-07 20:13:20 +01:00
curl_setopt ( $handle , CURLOPT_TIMEOUT , $timeout );
2009-12-04 11:58:37 +01:00
curl_multi_add_handle ( $mh , $handle );
$ch [ $handle ] = $handle ;
}
$str = false ;
$ans_count = 0 ;
$ans_arr = array ();
do {
while (( $mrc = curl_multi_exec ( $mh , $active )) == CURLM_CALL_MULTI_PERFORM )
;
while ( $info = curl_multi_info_read ( $mh )) {
debug ( " YK-KSM multi " , $info );
if ( $info [ 'result' ] == CURL_OK ) {
$str = curl_multi_getcontent ( $info [ 'handle' ]);
debug ( $str );
if ( preg_match ( " /status=OK/ " , $str )) {
$error = curl_error ( $info [ 'handle' ]);
$errno = curl_errno ( $info [ 'handle' ]);
$cinfo = curl_getinfo ( $info [ 'handle' ]);
debug ( " YK-KSM errno/error: " . $errno . " / " . $error , $cinfo );
$ans_count ++ ;
debug ( " found entry " );
$ans_arr [] = " url= " . $cinfo [ 'url' ] . " \n " . $str ;
}
if ( $ans_count >= $ans_req ) {
foreach ( $ch as $h ) {
curl_multi_remove_handle ( $mh , $h );
curl_close ( $h );
}
curl_multi_close ( $mh );
return $ans_arr ;
2009-12-02 18:32:20 +01:00
}
2009-12-04 11:58:37 +01:00
curl_multi_remove_handle ( $mh , $info [ 'handle' ]);
curl_close ( $info [ 'handle' ]);
unset ( $ch [ $info [ 'handle' ]]);
2009-12-02 18:32:20 +01:00
}
2009-12-07 20:13:20 +01:00
curl_multi_select ( $mh );
2009-12-02 18:32:20 +01:00
}
2009-12-04 11:58:37 +01:00
} while ( $active );
2009-12-04 17:11:00 +01:00
2009-12-04 11:58:37 +01:00
foreach ( $ch as $h ) {
curl_multi_remove_handle ( $mh , $h );
curl_close ( $h );
2009-12-02 18:32:20 +01:00
}
2009-12-04 11:58:37 +01:00
curl_multi_close ( $mh );
2009-12-04 17:11:00 +01:00
if ( $ans_count > 0 ) return $ans_arr ;
else return $str ;
2009-12-02 18:32:20 +01:00
}
2009-12-04 11:58:37 +01:00
2009-12-02 18:32:20 +01:00
}
?>