20 ) ? substr($key,0,20) : $key;
$len = strlen($key);
$hash = 0;
if (isset($_GET['pos']))
{
$hash = (!is_numeric($_GET['pos'])) ? 0 : $_GET['pos'];
$hash = (int) $hash;
$hash = $hash % 12;
}
$query = '
SELECT `id`, `name`, `access`, `start`, `end`, `request`,
`high`, `normal`, `limit`, `comment`
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;
$def = $row;
continue;
}
}
if ( $len > 0 )
{
die('Invalid key!');
}
// $def = Web service already defined partner access
//
// 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;
}
// Check keywords
// Key and pos are correct
// &acc=cat/23,25-32&req=landscape&lim=5&tpl=myxml
// Requested id list and authorized id list
// Both may empty
// Both can be build on differents basis cat/tag/list
// Both have to be convert in id list format
$req_access ='';
if (isset($_GET['pos']))
{
$req_access = check_target($_GET['acc']);
}
// on one hand $req_access, requested ids
$req_type = explode('/',$req_access);
$req_ids = explode( ',',$req_type[1] );
$req_list = expand_id_list( $req_ids );
if ($req_type[0]=='cat')
{
$req_list = convert_catlist($req_list);
}
if ($req_type[0]=='tag')
{
$req_list = get_image_ids_for_tags($req_list);
}
// echo $def['name'].'
';
// on the other hand $def['access'], authorized default ids
$def_type = explode('/',$def['access']);
$def_ids = explode( ',',$def_type[1] );
$def_list = expand_id_list( $def_ids );
if ($def_type[0]=='cat')
{
$def_list = convert_catlist($def_list);
}
if ($def_type[0]=='tag')
{
$def_list = get_image_ids_for_tags($def_list);
}
// could be no necessary, a surplus but we are obliged to
// Filter on forbidden_categories (default can have change from creation time)
$list = implode(',',$def_list);
$ret_ids = array();
$query = '
SELECT DISTINCT image_id
FROM '.IMAGE_CATEGORY_TABLE.'
WHERE
'.get_sql_condition_FandF
(
array
(
'forbidden_categories' => 'category_id',
'visible_categories' => 'category_id',
'visible_images' => 'image_id'
),
'', true
).'
AND image_id IN ('.$list.')
;';
$result = pwg_query($query);
while ($row = mysql_fetch_array($result))
{
$ret_ids[] = $row['image_id'];
}
$def_ids = $ret_ids;
// Notice: Filtering on forbidden_categories (from requested id list)
// is completely superfluous (see few lines below).
$req_ids = $req_list;
// if no requested ids then is the complete default
if (count($req_ids)==0)
{
$req_ids = $def_ids;
}
// Removing requested ids not in authorized access list
// if requested ids they must be in the complete default and only those
// will be assumed. (Including forbidden... )
$final = array();
foreach ( $req_ids as $req_id )
{
if ( in_array($req_id, $def_ids) )
{
$final[] = $req_id;
}
}
$final = array_unique ($final);
sort ($final);
// 77f1180bd215a0edf66939
// web_service.php?key=77f1180bd215&pos=3&acc=list/41,73,142,178,190,204,235-238&req=recent&lim=1&tpl=myxml
$request = (isset($_GET['req']))? $_GET['req']:$def['request'];
// if type of request is different from the authorized type then force it
if ( $def['request'] !== '' and $request !== $def['request'] )
{
$request = $def['request'];
}
// if it is not an official request then force it
// (remark that default request can no longer exist
// (later an Upgrade, or a remove) so...
$official = official_req();
if ( !in_array($request, $official ) )
{
$request = $official[0]; // default request is the first one
}
// limit belong default (remember $def['limit'] is always set)
$limit = (isset($_GET['limit']))? $_GET['limit']:$def['limit'];
$limit = (is_numeric($limit))? $limit:$def['limit'];
$limit = ( $limit < $def['limit'] ) ? $limit:$def['limit'];
// XML template
$tplfile = (isset($_GET['tpl']))? $_GET['tpl']:'default';
// FIXME additional controls are maybe needed on $tplfile
trigger_action('loc_begin_'.$request);
$template->set_filenames(array( $tplfile => 'XML/'. $tplfile .'.tpl'));
// Generate the request
include(PHPWG_ROOT_PATH. 'services/' .$request. '.php');
// +-----------------------------------------------------------------------+
// | XML/xhtml code display |
// +-----------------------------------------------------------------------+
header('Content-Type: text/xml; charset=UTF-8');
//header('Content-Type: text/html; charset='.$lang_info['charset']);
$template->parse($tplfile);
// echo 'Trace temporaire
';
// echo '$final:
' . var_dump($final);
//
die('');
// FIXME// FIXME// FIXME// FIXME// FIXME// FIXME// FIXME// FIXME
//------------------------------------------------------------ log informations
pwg_log($request, $stats_id, $tplfile); // or something like that
// 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.'
'.get_sql_condition_FandF
(
array
(
'forbidden_categories' => 'c.id',
'visible_categories' => 'c.id',
'visible_images' => 'i.id'
),
'AND'
);
// 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;
}
?>