20 ) ? substr($key,0,20) : $key; $len = strlen($key); &hash = 0; if (isset($_get['pos'])) { $hash = (!is_numeric($hash)) ? 0 : $_get['pos']; $hash = (int) $hash; $hash = $hash % 12; } $query = ' SELECT * FROM '.WEB_SERVICES_ACCESS_TABLE.' ;'; $result = pwg_query($query); while ($row = mysql_fetch_array($result)) { if ( substr( md5($row['name']),$hash,$len) == $key ) { $len = 0; continue; } } if ( $len > 0 ) { die('Invalid key!'); } // $def = Web service already defined partner access $def = $row; // // Now, the partner will get a reply in time // $stat_id = 'Web Service'; if (isset($_SERVER["HTTP_REFERER"]) and !eregi($_SERVER["HTTP_HOST"],$_SERVER["HTTP_REFERER"])) { $stats_id = substr($_SERVER["HTTP_REFERER"],7); $pos = strpos($stats_id,'/'); $stats_id = ( $pos>0 ) ? substr($stats_id,0,$pos) : $stats_id; } // FIXME// FIXME// FIXME// FIXME// FIXME// FIXME// FIXME// FIXME // Check keywords // Key and pos are correct // &acc=cat/23,25-32&req=landscape&lim=5&tpl=myxml // Check requested XML template // // Generate query // // Generate XML // // Log it // // Old code below //------------ Main security strategy --------------------- $partner_id = 'default'; // Security considerations: HTTP_REFERER and FOPEN // 1 - FOPEN doesn't update current HTTP_REFERER // 2 - HTTP_REFERER may be hidden/altered for lot of reasons. // 3 - By this process, you can log HTTP_REFERER of your partner (not yours). // 4 - Logging HTTP_REFERER needs declarative procedures in some countries. // 5 - Following those links can be considered as risky. // 6 - You can turn off, referer logging by $conf['ws-refback'] = false; // 7 - In the other hand, your partner may give his key to another web site. // Above all, this information is just an indication. // $conf['ws-refback'] : Default value is false. if (isset($_SERVER["HTTP_REFERER"]) and !eregi($_SERVER["HTTP_HOST"],$_SERVER["HTTP_REFERER"])) { $partner_id = substr($_SERVER["HTTP_REFERER"],7); $pos = strpos($partner_id,'/'); $partner_id = ( $pos>0 ) ? substr($partner_id,0,$pos) : $partner_id; } // $partner_id = Is used to check prohibited REFER site (but not only) // example: www.prohibited-access.be if ( isset($conf['ws-refback']) and $conf['ws-refback']) { $log_id = $partner_id; } else { $log_id = ''; // Would be set in time by process end } // $log_id = History log information // examples: forum.phpwebgallery.net // phpwebgallery.net // demo.phpwebgallery.net // $partner_id = strtolower($partner_id); // Prohibited REFER: $partner_id is compared (strtolower). // //----------------------------- Is a prohibited refer? if ( $partner_id !== 'default' ) { // Is Referer a prohibited site? // Compare requestor site to web service key table // Found and limit = 0 => die foreach ( $conf['ws_keys'] as $key => $vkey ) { if ( strtolower($vkey['id']) == $partner_id and $vkey['limit'] == 0 ) { pwg_log( 'WS Prohibited', 'Req.:'.$type, 'From: ws_keys['.$key.']' ); die($lang['access_forbiden']); } } } //----------------------------- Which access he will use? $access = check_ws_access( $conf['ws_keys'] ); // given key arg is compared asis (Take care of upper/lower case). parse_str($access['force'], $force); // $force contains all forced arguments // get requested arguments and apply limits $force['limit'] = ( isset($access['limit']) ) ? $access['limit'] : $conf['ws_limit'] ; $arg = force_arg_ws_limit( $force, $conf['ws_limit'] ); // $arg contains all retain query arguments // Warning about $arg !!! Warning !!! Warning !!! Warning !!! Warning !!! // specially to MOD developpers : // FOR SECURITY REASON NEVER USE extract() AGAINST $arg // ( $arg is like $_GET ) if ( is_numeric(isset($arg['cat'])) ) { $arg['cat']=floor($arg['cat']); } else { unset($arg['cat']); } // AND category_id is concatenated if requested or forced $cat_criterion = ''; if ( isset($arg['cat']) and ($arg['cat']) > 0 ) { $cat_criterion = ' AND ic.`category_id` ='.$arg['cat'].' '; } //-------------------------------------------- SQL Query statement building // Has to be tested against a LARGE configuration // for performance consideration // and maybe rewrite in some cases. // All below has to be check to respect code writing rule convention $query=' SELECT DISTINCT (i.`id`), i.`path` , i.`file` , i.`date_available` , i.`date_creation`, i.`tn_ext` , i.`name` , i.`filesize` , i.`storage_category_id` , i.`average_rate`, i.`comment` , i.`author` , i.`hit` ,i.`width` , i.`height` FROM `'.IMAGES_TABLE.'` AS i INNER JOIN `'.IMAGE_CATEGORY_TABLE.'` AS ic ON i.`id` = ic.`image_id` INNER JOIN `'.CATEGORIES_TABLE.'` AS c ON c.`id` = ic.`category_id` WHERE c.`status` = \'public\' AND i.`width` > 0 AND i.`height` > 0 AND i.`representative_ext` IS NULL '.$cat_criterion.' AND c.`id` NOT IN ('.$user['forbidden_categories'].') '; // AND c.`agreed_ws` = \'true\' (Obsolete specification replaced by force) $list = ( isset($arg['list']) ) ? $arg['list'] : ''; $type = $arg['type']; switch($type) { case ($type === 'random' or $type === 'listcat'): /* Random order */ $query .= ' ORDER BY RAND() DESC '; break; case ($type === 'list'): /* list on MBt & z0rglub request */ $query .= ' AND i.`id` IN ('.$list.') '; break; case $type === 'maxviewed': /* hit > 0 and hit desc order */ $query .= ' AND i.`hit` > 0 ORDER BY i.`hit` DESC, RAND() DESC '; break; case $type === 'recent': /* recent = Date_available desc order */ $query .= ' ORDER BY i.`date_available` DESC, RAND() DESC '; break; case $type === 'highrated': /* avg_rate > 0 and desc order */ // French Joke : Cette requete s'appelle officieusement l' "ail_gratte" $query .= ' AND i.`average_rate` > 0 ORDER BY i.`average_rate` DESC, RAND() DESC '; break; case $type === 'oldest': /* Date_available asc order */ $query .= ' ORDER BY i.`date_available` ASC, RAND() DESC '; break; case $type === 'lessviewed': /* hit asc order */ // French Joke : Cette requete s'appelle officieusement la "lessive" $query .= ' ORDER BY i.`hit` ASC, RAND() DESC '; break; case $type === 'lowrated': /* avg_rate asc order */ $query .= ' AND i.`average_rate` IS NOT NULL ORDER BY i.`average_rate` ASC, RAND() DESC '; break; case $type === 'undescribed': /* description missing */ // US/UK Joke : This request is unofficially named 'indiscribable' horror $query .= ' AND i.`comment` IS NULL ORDER BY RAND() DESC '; break; case $type === 'unnamed': /* new name missing */ $query .= ' AND i.`comment` IS NULL ORDER BY RAND() DESC '; break; case $type === 'portraits': /* width < height (portrait oriented) */ $query .= ' AND `width` < (`height` * 0.95) ORDER BY RAND() DESC '; break; case $type === 'landscapes': /* width > height (landscape oriented) */ $query .= ' AND `width` > (`height` * 1.05) ORDER BY RAND() DESC '; break; case $type === 'squares': /* width ~ height (square form) */ $query .= ' AND `width` BETWEEN (`height` * 0.95) AND (`height` * 1.05) ORDER BY RAND() DESC '; break; default: /* Just say: Goodbye !!! */ die($lang['access_forbiden']); } /* End switch */ $query .= ' LIMIT 0 , '.$arg['limit'].';'; $result = pwg_query( $query ); $attributes = array( 'width', 'height', 'author', 'date_creation', 'date_available', 'hit', 'filesize'); $xml = ' '; $hr_nbr = 0; $ns_nbr = 0; $tn_nbr = 0; if ( $log_id == '') { foreach ( $conf['ws_keys'] as $key => $vkey ) { if ( $vkey['id'] == $access['id'] ) { $log_id = 'R:#'.$key; break; } } } while ( $row = mysql_fetch_array( $result ) ) { $tn_nbr++; $item = ' 0 ) { $hr_nbr++; $item .= ' hrsrc="'.$high.'"'; $item .= ' hrwidth="'.$hrsize[0].'"'; $item .= ' hrheight="'.$hrsize[1].'"'; } } $xml .= $item.' />'; //-------------------------------------- picture ----- log informations // request_type ( R:#id_requester ), real_category_id [ request_number ], image_file_name ); pwg_log( $type.'('.$log_id.')', $row['storage_category_id'].'['.$tn_nbr.']', $row['file'] ); } $xml .= ' '; echo $xml; // Send XML //---------------------------------------- service ----- log informations $size = 'tn('.$tn_nbr.')'; // thumbnails if ( $ns_nbr > 0 ) { $size = '('.$ns_nbr.')'; // pictures } if ( $hr_nbr > 0 ) { $size = 'HR('.$hr_nbr.'/'.$tn_nbr.')'; // high res. } //pwg_log( 'Web service', 'Req.:'.$type, 'From:'.$log_id ); /*-- Web Service function Which access is correct for this resquest? Compare requestor key to web service key table If 'defined' => use that one If not => use default access If no 'defined' default => exit 'defined' : Obviously check period and not only defined access Return corresponding access (= an entry from web service key table) --*/ function check_ws_access( $ws_keys ) { $partnr = ( isset($_GET['key']) ) ? $_GET['key'] : 'default'; foreach ( $ws_keys as $key => $access ) { if ( $access['id'] == $partnr ) { break; } } if ( $access['id'] !== $partnr ) // Not found? =default. { $access = $ws_keys[0]; if ( $access['id'] !== 'default' ) // Check if it's really default { // definition die($lang['access_forbiden']); // No default access } } // Checking Dates... // Take care of that: my partner can be out of dates // but via default... Answer is NO. // With out of date period, a partner can be seen as prohibited partner // if you want to authorise him/her change $conf['ws_keys'] // Tests are done with server local time... if (isset($access['end']) and date('Y-m-d H:i:s')>$access['end']) { //-- Access ended? die($lang['access_forbiden']); //-- BTW prohibited } if (isset($access['start']) and date('Y-m-d H:i:s')<$access['start']) { //-- Access started? die($lang['access_forbiden']); } return $access; } /*-- Web Sevice function Force global arguments to ensure access restriction ( access defined in web service key table ) Considering the default limit as well and prohibited site case Return overided request ( overided $_GET ) --*/ function force_arg_ws_limit( $use, $default ) { if ( $use['limit'] < 1 ) { //-- Access deny die($lang['access_forbiden']); } $arg = $_GET; // what is required? if (!isset($arg['limit'])) { $arg['limit']=$use['limit']; } if (!is_numeric($arg['limit'])) { $arg['limit']=$use['limit']; } // ----------- use force arg if they are some foreach ( $use as $kuse => $vuse ) { if ( $kuse !== 'limit' ) { $arg[$kuse] = $vuse; } } $arg['limit'] = floor(min($arg['limit'], $use['limit'])); return $arg; } ?>