| [ Index ] |
|
Code source de b2evolution 2.1.0-beta |
1 <?php 2 /** 3 * This file implements the ItemQuery class. 4 * 5 * This file is part of the evoCore framework - {@link http://evocore.net/} 6 * See also {@link http://sourceforge.net/projects/evocms/}. 7 * 8 * @copyright (c)2003-2007 by Francois PLANQUE - {@link http://fplanque.net/} 9 * 10 * {@internal License choice 11 * - If you have received this file as part of a package, please find the license.txt file in 12 * the same folder or the closest folder above for complete license terms. 13 * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/) 14 * then you must choose one of the following licenses before using the file: 15 * - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php 16 * - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php 17 * }} 18 * 19 * {@internal Open Source relicensing agreement: 20 * }} 21 * 22 * @package evocore 23 * 24 * {@internal Below is a list of authors who have contributed to design/coding of this file: }} 25 * @author fplanque: Francois PLANQUE. 26 * 27 * @version $Id: _itemquery.class.php,v 1.2 2007/07/01 03:58:08 fplanque Exp $ 28 */ 29 if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' ); 30 31 load_class('_core/model/db/_sql.class.php'); 32 33 /** 34 * ItemQuery: help constructing queries on Items 35 * @package evocore 36 */ 37 class ItemQuery extends SQL 38 { 39 var $p; 40 var $title; 41 var $blog; 42 var $cat; 43 var $catsel; 44 var $show_statuses; 45 var $tags; 46 var $author; 47 var $assignees; 48 var $statuses; 49 var $types; 50 var $dstart; 51 var $dstop; 52 var $timestamp_min; 53 var $timestamp_max; 54 var $keywords; 55 var $phrase; 56 var $exact; 57 58 59 /** 60 * Constructor. 61 * 62 * @param string Name of table in database 63 * @param string Prefix of fields in the table 64 * @param string Name of the ID field (including prefix) 65 */ 66 function ItemQuery( $dbtablename, $dbprefix = '', $dbIDname ) 67 { 68 $this->dbtablename = $dbtablename; 69 $this->dbprefix = $dbprefix; 70 $this->dbIDname = $dbIDname; 71 72 $this->FROM( $this->dbtablename ); 73 } 74 75 76 /** 77 * Restrict to a specific post 78 */ 79 function where_ID( $p = '', $title = '' ) 80 { 81 $r = false; 82 83 $this->p = $p; 84 $this->title = $title; 85 86 // if a post number is specified, load that post 87 if( !empty($p) ) 88 { 89 $this->WHERE_and( $this->dbIDname.' = '. intval($p) ); 90 $r = true; 91 } 92 93 // if a post urltitle is specified, load that post 94 if( !empty( $title ) ) 95 { 96 global $DB; 97 $this->WHERE_and( $this->dbprefix.'urltitle = '.$DB->quote($title) ); 98 $r = true; 99 } 100 101 return $r; 102 } 103 104 105 /** 106 * Restrict to specific collection/chapters (blog/categories) 107 * 108 * @todo get rid of blog #1 109 * 110 * @param integer 111 * @param string List of cats to restrict to 112 * @param array Array of cats to restrict to 113 */ 114 function where_chapter( $blog, $cat = '', $catsel = array() ) 115 { 116 global $cat_array; // this is required for the cat_req() callback in compile_cat_array() 117 118 $blog = intval($blog); // Extra security 119 120 // Save for future use (permission checks..) 121 $this->blog = $blog; 122 123 $this->FROM_add( 'INNER JOIN T_postcats ON '.$this->dbIDname.' = postcat_post_ID 124 INNER JOIN T_categories ON postcat_cat_ID = cat_ID' ); 125 126 $BlogCache = & get_Cache('BlogCache'); 127 $current_Blog = $BlogCache->get_by_ID( $blog ); 128 $aggregate_coll_IDs = $current_Blog->get_setting('aggregate_coll_IDs'); 129 if( empty( $aggregate_coll_IDs ) ) 130 { // We only want posts from the current blog: 131 $this->WHERE_and( 'cat_blog_ID = '.$current_Blog->ID ); 132 } 133 else 134 { // We are aggregating posts from several blogs: 135 $this->WHERE_and( 'cat_blog_ID IN ('.$aggregate_coll_IDs.')' ); 136 } 137 138 139 $cat_array = NULL; 140 $cat_modifier = NULL; 141 142 // Compile the real category list to use: 143 // TODO: allow to pass the compiled vars directly to this class 144 compile_cat_array( $cat, $catsel, /* by ref */ $cat_array, /* by ref */ $cat_modifier, /* TODO $blog == 1 ? 0 : */ $blog ); 145 146 if( ! empty($cat_array) ) 147 { // We want to restict to some cats: 148 if( $cat_modifier == '-' ) 149 { 150 $eq = 'NOT IN'; 151 } 152 else 153 { 154 $eq = 'IN'; 155 } 156 $whichcat = 'postcat_cat_ID '. $eq.' ('.implode(',', $cat_array). ') '; 157 158 // echo $whichcat; 159 $this->WHERE_and( $whichcat ); 160 161 if( $cat_modifier == '*' ) 162 { // We want the categories combined! (i-e posts must be in ALL requested cats) 163 $this->GROUP_BY( $this->dbIDname.' HAVING COUNT(postcat_cat_ID) = '.count($cat_array) ); 164 } 165 } 166 } 167 168 169 /** 170 * Restrict to specific collection/chapters (blog/categories) 171 * 172 * @todo get rid of blog #1 173 * 174 * @param Blog 175 * @param array 176 * @param string 177 * @param string 'wide' to search in extra cats too, 'main' for main cat only 178 */ 179 function where_chapter2( & $Blog, $cat_array, $cat_modifier, $cat_focus = 'wide' ) 180 { 181 // Save for future use (permission checks..) 182 $this->blog = $Blog->ID; 183 $this->Blog = $Blog; 184 $this->cat_array = $cat_array; 185 $this->cat_modifier = $cat_modifier; 186 187 if( $cat_focus == 'wide' ) 188 { 189 $this->FROM_add( 'INNER JOIN T_postcats ON '.$this->dbIDname.' = postcat_post_ID 190 INNER JOIN T_categories ON postcat_cat_ID = cat_ID' ); 191 // fp> we try to restrict as close as possible to the posts but I don't know if it matters 192 $cat_ID_field = 'postcat_cat_ID'; 193 } 194 else 195 { 196 $this->FROM_add( 'INNER JOIN T_categories ON post_main_cat_ID = cat_ID' ); 197 $cat_ID_field = 'post_main_cat_ID'; 198 } 199 200 $aggregate_coll_IDs = $Blog->get_setting('aggregate_coll_IDs'); 201 if( empty( $aggregate_coll_IDs ) // This blog is not an aggregation anyway 202 || $cat_focus == 'main' ) // We are requesting a narrow search 203 { // We only want posts from the current blog: 204 $this->WHERE_and( 'cat_blog_ID = '.$Blog->ID ); 205 } 206 else 207 { // We are aggregating posts from several blogs: 208 $this->WHERE_and( 'cat_blog_ID IN ('.$aggregate_coll_IDs.')' ); 209 } 210 211 212 if( ! empty($cat_array) ) 213 { // We want to restict to some cats: 214 if( $cat_modifier == '-' ) 215 { 216 $eq = 'NOT IN'; 217 } 218 else 219 { 220 $eq = 'IN'; 221 } 222 $whichcat = $cat_ID_field.' '.$eq.' ('.implode(',', $cat_array). ') '; 223 224 // echo $whichcat; 225 $this->WHERE_and( $whichcat ); 226 227 if( $cat_modifier == '*' ) 228 { // We want the categories combined! (i-e posts must be in ALL requested cats) 229 $this->GROUP_BY( $this->dbIDname.' HAVING COUNT('.$cat_ID_field.') = '.count($cat_array) ); 230 } 231 } 232 } 233 234 235 /** 236 * Restrict to the visibility/sharing statuses we want to show 237 * 238 * @param array Restrict to these statuses 239 */ 240 function where_visibility( $show_statuses ) 241 { 242 $this->show_statuses = $show_statuses; 243 244 if( !isset( $this->blog ) ) 245 { 246 debug_die( 'Status restriction requires to work with aspecific blog first.' ); 247 } 248 249 $this->WHERE_and( statuses_where_clause( $show_statuses, $this->dbprefix, $this->blog ) ); 250 } 251 252 253 /** 254 * Restrict to specific tags 255 * 256 * @param string List of tags to restrict to 257 */ 258 function where_tags( $tags ) 259 { 260 global $DB; 261 262 $this->tags = $tags; 263 264 if( empty( $tags ) ) 265 { 266 return; 267 } 268 269 $tags = explode( ',', $tags ); 270 271 $this->FROM_add( 'INNER JOIN T_items__itemtag ON post_ID = itag_itm_ID 272 INNER JOIN T_items__tag ON (itag_tag_ID = tag_ID AND tag_name IN ('.$DB->quote($tags).') )' ); 273 } 274 275 276 /** 277 * Restrict to specific authors 278 * 279 * @param string List of authors to restrict to (must have been previously validated) 280 */ 281 function where_author( $author ) 282 { 283 $this->author = $author; 284 285 if( empty( $author ) ) 286 { 287 return; 288 } 289 290 if( substr( $author, 0, 1 ) == '-' ) 291 { // List starts with MINUS sign: 292 $eq = 'NOT IN'; 293 $author_list = substr( $author, 1 ); 294 } 295 else 296 { 297 $eq = 'IN'; 298 $author_list = $author; 299 } 300 301 $this->WHERE_and( $this->dbprefix.'creator_user_ID '.$eq.' ('.$author_list.')' ); 302 } 303 304 305 /** 306 * Restrict to specific assignees 307 * 308 * @param string List of assignees to restrict to (must have been previously validated) 309 */ 310 function where_assignees( $assignees ) 311 { 312 $this->assignees = $assignees; 313 314 if( empty( $assignees ) ) 315 { 316 return; 317 } 318 319 if( $assignees == '-' ) 320 { // List is ONLY a MINUS sign (we want only those not assigned) 321 $this->WHERE_and( $this->dbprefix.'assigned_user_ID IS NULL' ); 322 } 323 elseif( substr( $assignees, 0, 1 ) == '-' ) 324 { // List starts with MINUS sign: 325 $this->WHERE_and( '( '.$this->dbprefix.'assigned_user_ID IS NULL 326 OR '.$this->dbprefix.'assigned_user_ID NOT IN ('.substr( $assignees, 1 ).') )' ); 327 } 328 else 329 { 330 $this->WHERE_and( $this->dbprefix.'assigned_user_ID IN ('.$assignees.')' ); 331 } 332 } 333 334 335 /** 336 * Restrict to specific assignee or author 337 * 338 * @param integer assignee or author to restrict to (must have been previously validated) 339 */ 340 function where_author_assignee( $author_assignee ) 341 { 342 $this->author_assignee = $author_assignee; 343 344 if( empty( $author_assignee ) ) 345 { 346 return; 347 } 348 349 $this->WHERE_and( '( '.$this->dbprefix.'creator_user_ID = '. $author_assignee.' OR '. 350 $this->dbprefix.'assigned_user_ID = '.$author_assignee.' )' ); 351 } 352 353 354 /** 355 * Restrict to specific locale 356 * 357 * @param string locale to restrict to ('all' if you don't want to restrict) 358 */ 359 function where_locale( $locale ) 360 { 361 global $DB; 362 363 if( $locale == 'all' ) 364 { 365 return; 366 } 367 368 $this->WHERE_and( $this->dbprefix.'locale LIKE '.$DB->quote($locale.'%') ); 369 } 370 371 372 /** 373 * Restrict to specific (exetnded) statuses 374 * 375 * @param string List of assignees to restrict to (must have been previously validated) 376 */ 377 function where_statuses( $statuses ) 378 { 379 $this->statuses = $statuses; 380 381 if( empty( $statuses ) ) 382 { 383 return; 384 } 385 386 if( $statuses == '-' ) 387 { // List is ONLY a MINUS sign (we want only those not assigned) 388 $this->WHERE_and( $this->dbprefix.'pst_ID IS NULL' ); 389 } 390 elseif( substr( $statuses, 0, 1 ) == '-' ) 391 { // List starts with MINUS sign: 392 $this->WHERE_and( '( '.$this->dbprefix.'pst_ID IS NULL 393 OR '.$this->dbprefix.'pst_ID NOT IN ('.substr( $statuses, 1 ).') )' ); 394 } 395 else 396 { 397 $this->WHERE_and( $this->dbprefix.'pst_ID IN ('.$statuses.')' ); 398 } 399 } 400 401 402 /** 403 * Restrict to specific item types 404 * 405 * @param string List of types to restrict to (must have been previously validated) 406 */ 407 function where_types( $types ) 408 { 409 $this->types = $types; 410 411 if( empty( $types ) ) 412 { 413 return; 414 } 415 416 if( $types == '-' ) 417 { // List is ONLY a MINUS sign (we want only those not assigned) 418 $this->WHERE_and( $this->dbprefix.'ptyp_ID IS NULL' ); 419 } 420 elseif( substr( $types, 0, 1 ) == '-' ) 421 { // List starts with MINUS sign: 422 $this->WHERE_and( '( '.$this->dbprefix.'ptyp_ID IS NULL 423 OR '.$this->dbprefix.'ptyp_ID NOT IN ('.substr( $types, 1 ).') )' ); 424 } 425 else 426 { 427 $this->WHERE_and( $this->dbprefix.'ptyp_ID IN ('.$types.')' ); 428 } 429 } 430 431 432 /** 433 * Restricts to a specific date range. (despite thje 'start' in the name 434 * 435 * Priorities: 436 * -dstart and/or dstop 437 * -week + m 438 * -m 439 * @todo -dstart + x days 440 * @see ItemList2::get_advertised_start_date() 441 * 442 * @param string YYYYMMDDHHMMSS (everything after YYYY is optional) or '' 443 * @param integer week number or '' 444 * @param string YYYYMMDDHHMMSS to start at, '' for first available 445 * @param string YYYYMMDDHHMMSS to stop at 446 * @param mixed Do not show posts before this timestamp, can be 'now' 447 * @param mixed Do not show posts after this timestamp, can be 'now' 448 */ 449 function where_datestart( $m = '', $w = '', $dstart = '', $dstop = '', $timestamp_min = '', $timestamp_max = 'now' ) 450 { 451 global $time_difference; 452 453 $this->m = $m; 454 $this->w = $w; 455 $this->dstart = $dstart; 456 $this->dstop = $dstop; 457 $this->timestamp_min = $timestamp_min; 458 $this->timestamp_max = $timestamp_max; 459 460 461 $start_is_set = false; 462 $stop_is_set = false; 463 464 465 // if a start date is specified in the querystring, crop anything before 466 if( !empty($dstart) ) 467 { 468 // Add trailing 0s: YYYYMMDDHHMMSS 469 $dstart0 = $dstart.'00000000000000'; // TODO: this is NOT correct, should be 0101 for month 470 471 $dstart_mysql = substr($dstart0,0,4).'-'.substr($dstart0,4,2).'-'.substr($dstart0,6,2).' ' 472 .substr($dstart0,8,2).':'.substr($dstart0,10,2).':'.substr($dstart0,12,2); 473 474 $this->WHERE_and( $this->dbprefix.'datestart >= \''.$dstart_mysql.'\' 475 OR ( '.$this->dbprefix.'datedeadline IS NULL AND '.$this->dbprefix.'datestart >= \''.$dstart_mysql.'\' )' ); 476 477 $start_is_set = true; 478 } 479 480 481 // if a stop date is specified in the querystring, crop anything before 482 if( !empty($dstop) ) 483 { 484 switch( strlen( $dstop ) ) 485 { 486 case '4': 487 // We have only year, add one to year 488 $dstop_mysql = ($dstop+1).'-01-01 00:00:00'; 489 break; 490 491 case '6': 492 // We have year month, add one to month 493 $dstop_mysql = date("Y-m-d H:i:s ", mktime(0, 0, 0, substr($dstop,4,2)+1, 01, substr($dstop,0,4))); 494 break; 495 496 case '8': 497 // We have year mounth day, add one to day 498 $dstop_mysql = date("Y-m-d H:i:s ", mktime(0, 0, 0, substr($dstop,4,2), (substr($dstop,6,2) + 1 ), substr($dstop,0,4))); 499 break; 500 501 case '10': 502 // We have year mounth day hour, add one to hour 503 $dstop_mysql = date("Y-m-d H:i:s ", mktime( ( substr($dstop,8,2) + 1 ), 0, 0, substr($dstop,4,2), substr($dstop,6,2), substr($dstop,0,4))); 504 break; 505 506 case '12': 507 // We have year mounth day hour minute, add one to minute 508 $dstop_mysql = date("Y-m-d H:i:s ", mktime( substr($dstop,8,2), ( substr($dstop,8,2) + 1 ), 0, substr($dstop,4,2), substr($dstop,6,2), substr($dstop,0,4))); 509 break; 510 511 default: 512 // add one to second 513 $dstop_mysql = substr($dstop,0,4).'-'.substr($dstop,4,2).'-'.substr($dstop,6,2).' ' 514 .substr($dstop,8,2).':'.substr($dstop,10,2).':'.( substr( $dstop,12,2) + 1 ); 515 } 516 517 $this->WHERE_and( $this->dbprefix.'datestart < \''.$dstop_mysql.'\'' ); // NOT <= comparator because we compare to the superior stop date 518 519 $stop_is_set = true; 520 } 521 522 523 if( !$start_is_set || !$stop_is_set ) 524 { 525 526 if( !is_null($w) // Note: week # can be 0 527 && strlen($m) == 4 ) 528 { // If a week number is specified (with a year) 529 530 // Note: we use PHP to calculate week boundaries in order to handle weeks 531 // that overlap 2 years properly, even when start on week is monday (which MYSQL won't handle properly) 532 $start_date_for_week = get_start_date_for_week( $m, $w, locale_startofweek() ); 533 534 $this->WHERE_and( $this->dbprefix."datestart >= '".date('Y-m-d',$start_date_for_week)."'" ); 535 $this->WHERE_and( $this->dbprefix."datestart < '".date('Y-m-d',$start_date_for_week+604800 )."'" ); // + 7 days 536 537 $start_is_set = true; 538 $stop_is_set = true; 539 } 540 elseif( !empty($m) ) 541 { // We want to restrict on an interval: 542 $this->WHERE_and( 'EXTRACT(YEAR FROM '.$this->dbprefix.'datestart)='.intval(substr($m,0,4)) ); 543 if( strlen($m) > 5 ) 544 $this->WHERE_and( 'EXTRACT(MONTH FROM '.$this->dbprefix.'datestart)='.intval(substr($m,4,2)) ); 545 if( strlen($m) > 7 ) 546 $this->WHERE_and( 'EXTRACT(DAY FROM '.$this->dbprefix.'datestart)='.intval(substr($m,6,2)) ); 547 if( strlen($m) > 9 ) 548 $this->WHERE_and( 'EXTRACT(HOUR FROM '.$this->dbprefix.'datestart)='.intval(substr($m,8,2)) ); 549 if( strlen($m) > 11 ) 550 $this->WHERE_and( 'EXTRACT(MINUTE FROM '.$this->dbprefix.'datestart)='.intval(substr($m,10,2)) ); 551 if( strlen($m) > 13 ) 552 $this->WHERE_and( 'EXTRACT(SECOND FROM '.$this->dbprefix.'datestart)='.intval(substr($m,12,2)) ); 553 554 $start_is_set = true; 555 $stop_is_set = true; 556 } 557 558 } 559 560 561 // TODO: start + x days 562 // TODO: stop - x days 563 564 565 // SILENT limits! 566 567 // Timestamp limits: 568 if( $timestamp_min == 'now' ) 569 { 570 // echo 'hide past'; 571 $timestamp_min = time(); 572 } 573 if( !empty($timestamp_min) ) 574 { // Hide posts before 575 // echo 'hide before '.$timestamp_min; 576 $date_min = date('Y-m-d H:i:s', $timestamp_min + $time_difference ); 577 $this->WHERE_and( $this->dbprefix.'datestart >= \''. $date_min.'\'' ); 578 } 579 580 if( $timestamp_max == 'now' ) 581 { 582 // echo 'hide future'; 583 $timestamp_max = time(); 584 } 585 if( !empty($timestamp_max) ) 586 { // Hide posts after 587 // echo 'after'; 588 $date_max = date('Y-m-d H:i:s', $timestamp_max + $time_difference ); 589 $this->WHERE_and( $this->dbprefix.'datestart <= \''. $date_max.'\'' ); 590 } 591 592 } 593 594 595 /** 596 * Restrict with keywords 597 * 598 * @param string Keyword search string 599 * @param mixed Search for entire phrase or for individual words 600 * @param mixed Require exact match of title or contents 601 */ 602 function where_keywords( $keywords, $phrase, $exact ) 603 { 604 global $DB; 605 606 $this->keywords = $keywords; 607 $this->phrase = $phrase; 608 $this->exact = $exact; 609 610 if( empty($keywords) ) 611 { 612 return; 613 } 614 615 $search = ''; 616 617 if( $exact ) 618 { // We want exact match of title or contents 619 $n = ''; 620 } 621 else 622 { // The words/sentence are/is to be included in in the title or the contents 623 $n = '%'; 624 } 625 626 if( ($phrase == '1') or ($phrase == 'sentence') ) 627 { // Sentence search 628 $keywords = $DB->escape(trim($keywords)); 629 $search .= '('.$this->dbprefix.'title LIKE \''. $n. $keywords. $n. '\') OR ('.$this->dbprefix.'content LIKE \''. $n. $keywords. $n.'\')'; 630 } 631 else 632 { // Word search 633 if( strtoupper( $phrase ) == 'OR' ) 634 $swords = 'OR'; 635 else 636 $swords = 'AND'; 637 638 // puts spaces instead of commas 639 $keywords = preg_replace('/, +/', '', $keywords); 640 $keywords = str_replace(',', ' ', $keywords); 641 $keywords = str_replace('"', ' ', $keywords); 642 $keywords = trim($keywords); 643 $keyword_array = explode(' ',$keywords); 644 $join = ''; 645 for ( $i = 0; $i < count($keyword_array); $i++) 646 { 647 $search .= ' '. $join. ' ( ('.$this->dbprefix.'title LIKE \''. $n. $DB->escape($keyword_array[$i]). $n. '\') 648 OR ('.$this->dbprefix.'content LIKE \''. $n. $DB->escape($keyword_array[$i]). $n.'\') ) '; 649 $join = $swords; 650 } 651 } 652 653 //echo $search; 654 $this->WHERE_and( $search ); 655 } 656 657 658 } 659 660 661 /* 662 * $Log: _itemquery.class.php,v $ 663 * Revision 1.2 2007/07/01 03:58:08 fplanque 664 * cat_array cleanup/debug 665 * 666 * Revision 1.1 2007/06/25 11:00:28 fplanque 667 * MODULES (refactored MVC) 668 * 669 * Revision 1.19 2007/06/11 22:01:53 blueyed 670 * doc fixes 671 * 672 * Revision 1.18 2007/05/27 00:35:26 fplanque 673 * tag display + tag filtering 674 * 675 * Revision 1.17 2007/04/26 00:11:12 fplanque 676 * (c) 2007 677 * 678 * Revision 1.16 2007/03/26 12:59:18 fplanque 679 * basic pages support 680 * 681 * Revision 1.15 2007/03/19 21:57:36 fplanque 682 * ItemLists: $cat_focus and $unit extensions 683 * 684 * Revision 1.14 2007/02/14 15:04:35 waltercruz 685 * Changing the date queries to the EXTRACT syntax 686 * 687 * Revision 1.13 2007/02/06 13:37:45 waltercruz 688 * Changing double quotes to single quotes 689 * 690 * Revision 1.12 2007/01/29 20:04:23 blueyed 691 * MFB: Fixed inclusion of sub-categories in item list 692 * 693 * Revision 1.11 2006/12/17 23:42:38 fplanque 694 * Removed special behavior of blog #1. Any blog can now aggregate any other combination of blogs. 695 * Look into Advanced Settings for the aggregating blog. 696 * There may be side effects and new bugs created by this. Please report them :] 697 * 698 * Revision 1.10 2006/11/24 18:27:24 blueyed 699 * Fixed link to b2evo CVS browsing interface in file docblocks 700 * 701 * Revision 1.9 2006/09/07 00:48:55 fplanque 702 * lc parameter for locale filtering of posts 703 */ 704 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Thu Nov 29 23:58:50 2007 | par Balluche grâce à PHPXref 0.7 |
|