1<?php 2// +-----------------------------------------------------------------------+ 3// | This file is part of Piwigo. | 4// | | 5// | For copyright and license information, please view the COPYING.txt | 6// | file that was distributed with this source code. | 7// +-----------------------------------------------------------------------+ 8 9 10/** 11 * returns a prefix for each url link on displayed page 12 * and return an empty string for current path 13 * @return string 14 */ 15function get_root_url() 16{ 17 global $page; 18 if ( ($root_url = @$page['root_path']) == null ) 19 {// TODO - add HERE the possibility to call PWG functions from external scripts 20 $root_url = PHPWG_ROOT_PATH; 21 if ( strncmp($root_url, './', 2) == 0 ) 22 { 23 return substr($root_url, 2); 24 } 25 } 26 return $root_url; 27} 28 29/** 30 * returns the absolute url to the root of PWG 31 * @param boolean with_scheme if false - does not add http://toto.com 32 */ 33function get_absolute_root_url($with_scheme=true) 34{ 35 // TODO - add HERE the possibility to call PWG functions from external scripts 36 $url = ''; 37 if ($with_scheme) 38 { 39 $is_https = false; 40 if (isset($_SERVER['HTTPS']) && 41 ((strtolower($_SERVER['HTTPS']) == 'on') or ($_SERVER['HTTPS'] == 1))) 42 { 43 $is_https = true; 44 $url .= 'https://'; 45 } 46 else 47 { 48 $url .= 'http://'; 49 } 50 if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) 51 { 52 $url .= $_SERVER['HTTP_X_FORWARDED_HOST']; 53 } 54 else 55 { 56 $url .= $_SERVER['HTTP_HOST']; 57 if ( (!$is_https && $_SERVER['SERVER_PORT'] != 80) 58 ||($is_https && $_SERVER['SERVER_PORT'] != 443)) 59 { 60 $url_port = ':'.$_SERVER['SERVER_PORT']; 61 if (strrchr($url, ':') != $url_port) 62 { 63 $url .= $url_port; 64 } 65 } 66 } 67 } 68 $url .= cookie_path(); 69 return $url; 70} 71 72/** 73 * adds one or more _GET style parameters to an url 74 * example: add_url_params('/x', array('a'=>'b')) returns /x?a=b 75 * add_url_params('/x?cat_id=10', array('a'=>'b')) returns /x?cat_id=10&a=b 76 * @param string url 77 * @param array params 78 * @return string 79 */ 80function add_url_params($url, $params, $arg_separator='&' ) 81{ 82 if ( !empty($params) ) 83 { 84 assert( is_array($params) ); 85 $is_first = true; 86 foreach($params as $param=>$val) 87 { 88 if ($is_first) 89 { 90 $is_first = false; 91 $url .= ( strpos($url, '?')===false ) ? '?' : $arg_separator; 92 } 93 else 94 { 95 $url .= $arg_separator; 96 } 97 $url .= $param; 98 if (isset($val)) 99 { 100 $url .= '='.$val; 101 } 102 } 103 } 104 return $url; 105} 106 107/** 108 * build an index URL for a specific section 109 * 110 * @param array 111 * @return string 112 */ 113function make_index_url($params = array()) 114{ 115 global $conf; 116 $url = get_root_url().'index'; 117 if ($conf['php_extension_in_urls']) 118 { 119 $url .= '.php'; 120 } 121 if ($conf['question_mark_in_urls']) 122 { 123 $url .= '?'; 124 } 125 126 $url_before_params = $url; 127 128 $url.= make_section_in_url($params); 129 $url = add_well_known_params_in_url($url, $params); 130 131 if ($url == $url_before_params) 132 { 133 $url = get_absolute_root_url( url_is_remote($url) ); 134 } 135 136 return $url; 137} 138 139/** 140 * build an index URL with current page parameters, but with redefinitions 141 * and removes. 142 * 143 * duplicate_index_url( array( 144 * 'category' => array('id'=>12, 'name'=>'toto'), 145 * array('start') 146 * ) will create an index URL on the current section (categories), but on 147 * a redefined category and without the start URL parameter. 148 * 149 * @param array redefined keys 150 * @param array removed keys 151 * @return string 152 */ 153function duplicate_index_url($redefined = array(), $removed = array()) 154{ 155 return make_index_url( 156 params_for_duplication($redefined, $removed) 157 ); 158} 159 160/** 161 * returns $page global array with key redefined and key removed 162 * 163 * @param array redefined keys 164 * @param array removed keys 165 * @return array 166 */ 167function params_for_duplication($redefined, $removed) 168{ 169 global $page; 170 171 $params = $page; 172 173 foreach ($removed as $param_key) 174 { 175 unset($params[$param_key]); 176 } 177 178 foreach ($redefined as $redefined_param => $redefined_value) 179 { 180 $params[$redefined_param] = $redefined_value; 181 } 182 183 return $params; 184} 185 186/** 187 * create a picture URL with current page parameters, but with redefinitions 188 * and removes. See duplicate_index_url. 189 * 190 * @param array redefined keys 191 * @param array removed keys 192 * @return string 193 */ 194function duplicate_picture_url($redefined = array(), $removed = array()) 195{ 196 return make_picture_url( 197 params_for_duplication($redefined, $removed) 198 ); 199} 200 201/** 202 * create a picture URL on a specific section for a specific picture 203 * 204 * @param array 205 * @return string 206 */ 207function make_picture_url($params) 208{ 209 global $conf; 210 211 $url = get_root_url().'picture'; 212 if ($conf['php_extension_in_urls']) 213 { 214 $url .= '.php'; 215 } 216 if ($conf['question_mark_in_urls']) 217 { 218 $url .= '?'; 219 } 220 $url.= '/'; 221 switch ( $conf['picture_url_style'] ) 222 { 223 case 'id-file': 224 $url .= $params['image_id']; 225 if ( isset($params['image_file']) ) 226 { 227 $url .= '-'.str2url(get_filename_wo_extension($params['image_file'])); 228 } 229 break; 230 case 'file': 231 if ( isset($params['image_file']) ) 232 { 233 $fname_wo_ext = get_filename_wo_extension($params['image_file']); 234 if ( ord($fname_wo_ext)>ord('9') or !preg_match('/^\d+(-|$)/', $fname_wo_ext) ) 235 { 236 $url .= $fname_wo_ext; 237 break; 238 } 239 } 240 default: 241 $url .= $params['image_id']; 242 } 243 if ( !isset($params['category'] ) ) 244 {// make urls shorter ... 245 unset( $params['flat'] ); 246 } 247 $url .= make_section_in_url($params); 248 $url = add_well_known_params_in_url($url, $params); 249 return $url; 250} 251 252/** 253 *adds to the url the chronology and start parameters 254*/ 255function add_well_known_params_in_url($url, $params) 256{ 257 if ( isset($params['chronology_field']) ) 258 { 259 $url .= '/'. $params['chronology_field']; 260 $url .= '-'. $params['chronology_style']; 261 if ( isset($params['chronology_view']) ) 262 { 263 $url .= '-'. $params['chronology_view']; 264 } 265 if ( !empty($params['chronology_date']) ) 266 { 267 $url .= '-'. implode('-', $params['chronology_date'] ); 268 } 269 } 270 271 if (isset($params['flat'])) 272 { 273 $url.= '/flat'; 274 } 275 276 if (isset($params['start']) and $params['start'] > 0) 277 { 278 $url.= '/start-'.$params['start']; 279 } 280 return $url; 281} 282 283/** 284 * return the section token of an index or picture URL. 285 * 286 * Depending on section, other parameters are required (see function code 287 * for details) 288 * 289 * @param array 290 * @return string 291 */ 292function make_section_in_url($params) 293{ 294 global $conf; 295 $section_string = ''; 296 $section = @$params['section']; 297 if (!isset($section)) 298 { 299 $section_of = array( 300 'category' => 'categories', 301 'tags' => 'tags', 302 'list' => 'list', 303 'search' => 'search', 304 ); 305 306 foreach ($section_of as $param => $s) 307 { 308 if (isset($params[$param])) 309 { 310 $section = $s; 311 } 312 } 313 314 if (!isset($section)) 315 { 316 $section = 'none'; 317 } 318 } 319 320 switch($section) 321 { 322 case 'categories' : 323 { 324 if (!isset($params['category'])) 325 { 326 $section_string.= '/categories'; 327 } 328 else 329 { 330 isset($params['category']['name']) or trigger_error( 331 'make_section_in_url category name not set', E_USER_WARNING 332 ); 333 334 array_key_exists('permalink', $params['category']) or trigger_error( 335 'make_section_in_url category permalink not set', E_USER_WARNING 336 ); 337 338 $section_string.= '/category/'; 339 if ( empty($params['category']['permalink']) ) 340 { 341 $section_string.= $params['category']['id']; 342 if ( $conf['category_url_style']=='id-name' ) 343 { 344 $section_string.= '-'.str2url($params['category']['name']); 345 } 346 } 347 else 348 { 349 $section_string.= $params['category']['permalink']; 350 } 351 352 if (isset($params['combined_categories'])) 353 { 354 foreach ($params['combined_categories'] as $category) 355 { 356 $section_string.= '/'; 357 358 if ( empty($category['permalink']) ) 359 { 360 $section_string.= $category['id']; 361 if ( $conf['category_url_style']=='id-name' ) 362 { 363 $section_string.= '-'.str2url($category['name']); 364 } 365 } 366 else 367 { 368 $section_string.= $category['permalink']; 369 } 370 } 371 } 372 } 373 374 break; 375 } 376 case 'tags' : 377 { 378 $section_string.= '/tags'; 379 380 foreach ($params['tags'] as $tag) 381 { 382 switch ( $conf['tag_url_style'] ) 383 { 384 case 'id': 385 $section_string.= '/'.$tag['id']; 386 break; 387 case 'tag': 388 if (isset($tag['url_name'])) 389 { 390 $section_string.= '/'.$tag['url_name']; 391 break; 392 } 393 default: 394 $section_string.= '/'.$tag['id']; 395 if (isset($tag['url_name'])) 396 { 397 $section_string.= '-'.$tag['url_name']; 398 } 399 } 400 } 401 402 break; 403 } 404 case 'search' : 405 { 406 $section_string.= '/search/'.$params['search']; 407 break; 408 } 409 case 'list' : 410 { 411 $section_string.= '/list/'.implode(',', $params['list']); 412 break; 413 } 414 case 'none' : 415 { 416 break; 417 } 418 default : 419 { 420 $section_string.= '/'.$section; 421 } 422 } 423 424 return $section_string; 425} 426 427/** 428 * the reverse of make_section_in_url 429 * returns the 'section' (categories/tags/...) and the data associated with it 430 * 431 * Depending on section, other parameters are returned (category/tags/list/...) 432 * 433 * @param array of url tokens to parse 434 * @param int the index in the array of url tokens; in/out 435 * @return array 436 */ 437function parse_section_url( $tokens, &$next_token) 438{ 439 $page=array(); 440 if (strncmp(@$tokens[$next_token], 'categor', 7)==0 ) 441 { 442 $page['section'] = 'categories'; 443 $next_token++; 444 445 $i = $next_token; 446 $loop_counter = 0; 447 448 while (isset($tokens[$next_token])) 449 { 450 if ($loop_counter++ > count($tokens)+10){die('infinite loop?');} 451 452 if ( 453 strpos($tokens[$next_token], 'created-')===0 454 or strpos($tokens[$next_token], 'posted-')===0 455 or strpos($tokens[$next_token], 'start-')===0 456 or strpos($tokens[$next_token], 'startcat-')===0 457 or 'flat' == $tokens[$next_token] 458 ) 459 { 460 break; 461 } 462 463 if (preg_match('/^(\d+)(?:-(.+))?$/', $tokens[$next_token], $matches)) 464 { 465 if ( isset($matches[2]) ) 466 $page['hit_by']['cat_url_name'] = $matches[2]; 467 468 if (!isset($page['category'])) 469 { 470 $page['category'] = $matches[1]; 471 } 472 else 473 { 474 $page['combined_categories'][] = $matches[1]; 475 } 476 $next_token++; 477 } 478 else 479 {// try a permalink 480 $maybe_permalinks = array(); 481 $current_token = $next_token; 482 while ( isset($tokens[$current_token]) 483 and strpos($tokens[$current_token], 'created-')!==0 484 and strpos($tokens[$current_token], 'posted-')!==0 485 and strpos($tokens[$next_token], 'start-')!==0 486 and strpos($tokens[$next_token], 'startcat-')!==0 487 and $tokens[$current_token] != 'flat') 488 { 489 if (empty($maybe_permalinks)) 490 { 491 $maybe_permalinks[] = $tokens[$current_token]; 492 } 493 else 494 { 495 $maybe_permalinks[] = 496 $maybe_permalinks[count($maybe_permalinks)-1] 497 . '/' . $tokens[$current_token]; 498 } 499 $current_token++; 500 } 501 502 if ( count($maybe_permalinks) ) 503 { 504 $cat_id = get_cat_id_from_permalinks($maybe_permalinks, $perma_index); 505 if ( isset($cat_id) ) 506 { 507 $next_token += $perma_index+1; 508 509 if (!isset($page['category'])) 510 { 511 $page['category'] = $cat_id; 512 $page['hit_by']['cat_permalink'] = $maybe_permalinks[$perma_index]; 513 } 514 else 515 { 516 $page['combined_categories'][] = $cat_id; 517 } 518 } 519 else 520 { 521 page_not_found(l10n('Permalink for album not found')); 522 } 523 } 524 } 525 } 526 527 if (isset($page['category'])) 528 { 529 $result = get_cat_info($page['category']); 530 if (empty($result)) 531 { 532 page_not_found(l10n('Requested album does not exist')); 533 } 534 $page['category']=$result; 535 } 536 537 if (isset($page['combined_categories'])) 538 { 539 $combined_categories = array(); 540 541 foreach ($page['combined_categories'] as $cat_id) 542 { 543 $result = get_cat_info($cat_id); 544 if (empty($result)) 545 { 546 page_not_found(l10n('Requested album does not exist')); 547 } 548 549 $combined_categories[] = $result; 550 } 551 552 $page['combined_categories'] = $combined_categories; 553 } 554 } 555 elseif ( 'tags' == @$tokens[$next_token] ) 556 { 557 global $conf; 558 559 $page['section'] = 'tags'; 560 $page['tags'] = array(); 561 562 $next_token++; 563 $i = $next_token; 564 565 $requested_tag_ids = array(); 566 $requested_tag_url_names = array(); 567 568 while (isset($tokens[$i])) 569 { 570 if (strpos($tokens[$i], 'created-')===0 571 or strpos($tokens[$i], 'posted-')===0 572 or strpos($tokens[$i], 'start-')===0 ) 573 break; 574 575 if ( $conf['tag_url_style'] != 'tag' and preg_match('/^(\d+)(?:-(.*)|)$/', $tokens[$i], $matches) ) 576 { 577 $requested_tag_ids[] = $matches[1]; 578 } 579 else 580 { 581 $requested_tag_url_names[] = $tokens[$i]; 582 } 583 $i++; 584 } 585 $next_token = $i; 586 587 if ( empty($requested_tag_ids) && empty($requested_tag_url_names) ) 588 { 589 bad_request('at least one tag required'); 590 } 591 592 $page['tags'] = find_tags($requested_tag_ids, $requested_tag_url_names); 593 if ( empty($page['tags']) ) 594 { 595 page_not_found(l10n('Requested tag does not exist'), get_root_url().'tags.php' ); 596 } 597 } 598 elseif ( 'favorites' == @$tokens[$next_token] ) 599 { 600 $page['section'] = 'favorites'; 601 $next_token++; 602 } 603 elseif ('most_visited' == @$tokens[$next_token]) 604 { 605 $page['section'] = 'most_visited'; 606 $next_token++; 607 } 608 elseif ('best_rated' == @$tokens[$next_token]) 609 { 610 $page['section'] = 'best_rated'; 611 $next_token++; 612 } 613 elseif ('recent_pics' == @$tokens[$next_token]) 614 { 615 $page['section'] = 'recent_pics'; 616 $next_token++; 617 } 618 elseif ('recent_cats' == @$tokens[$next_token]) 619 { 620 $page['section'] = 'recent_cats'; 621 $next_token++; 622 } 623 elseif ('search' == @$tokens[$next_token]) 624 { 625 $page['section'] = 'search'; 626 $next_token++; 627 628 preg_match('/(\d+)/', @$tokens[$next_token], $matches); 629 if (!isset($matches[1])) 630 { 631 bad_request('search identifier is missing'); 632 } 633 $page['search'] = $matches[1]; 634 $next_token++; 635 } 636 elseif ('list' == @$tokens[$next_token]) 637 { 638 $page['section'] = 'list'; 639 $next_token++; 640 641 $page['list'] = array(); 642 643 // No pictures 644 if (empty($tokens[$next_token])) 645 { 646 // Add dummy element list 647 $page['list'][] = -1; 648 } 649 // With pictures list 650 else 651 { 652 if (!preg_match('/^\d+(,\d+)*$/', $tokens[$next_token])) 653 { 654 bad_request('wrong format on list GET parameter'); 655 } 656 foreach (explode(',', $tokens[$next_token]) as $image_id) 657 { 658 $page['list'][] = $image_id; 659 } 660 } 661 $next_token++; 662 } 663 return $page; 664} 665 666/** 667 * the reverse of add_well_known_params_in_url 668 * parses start, flat and chronology from url tokens 669*/ 670function parse_well_known_params_url($tokens, &$i) 671{ 672 $page = array(); 673 while (isset($tokens[$i])) 674 { 675 if ( 'flat' == $tokens[$i] ) 676 { 677 // indicate a special list of images 678 $page['flat'] = true; 679 } 680 elseif (strpos($tokens[$i], 'created-')===0 or strpos($tokens[$i], 'posted-')===0) 681 { 682 $chronology_tokens = explode('-', $tokens[$i] ); 683 684 $page['chronology_field'] = $chronology_tokens[0]; 685 686 array_shift($chronology_tokens); 687 $page['chronology_style'] = $chronology_tokens[0]; 688 689 array_shift($chronology_tokens); 690 if ( count($chronology_tokens)>0 ) 691 { 692 if ('list'==$chronology_tokens[0] or 693 'calendar'==$chronology_tokens[0]) 694 { 695 $page['chronology_view'] = $chronology_tokens[0]; 696 array_shift($chronology_tokens); 697 } 698 $page['chronology_date'] = $chronology_tokens; 699 } 700 } 701 elseif (preg_match('/^start-(\d+)/', $tokens[$i], $matches)) 702 { 703 $page['start'] = $matches[1]; 704 } 705 elseif (preg_match('/^startcat-(\d+)/', $tokens[$i], $matches)) 706 { 707 $page['startcat'] = $matches[1]; 708 } 709 $i++; 710 } 711 return $page; 712} 713 714 715/** 716 * @param id image id 717 * @param what_part string one of 'e' (element), 'r' (representative) 718 */ 719function get_action_url($id, $what_part, $download) 720{ 721 $params = array( 722 'id' => $id, 723 'part' => $what_part, 724 ); 725 if ($download) 726 { 727 $params['download'] = null; 728 } 729 730 return add_url_params(get_root_url().'action.php', $params); 731} 732 733/* 734 * @param element_info array containing element information from db; 735 * at least 'id', 'path' should be present 736 */ 737function get_element_url($element_info) 738{ 739 $url = $element_info['path']; 740 if ( !url_is_remote($url) ) 741 { 742 $url = embellish_url(get_root_url().$url); 743 } 744 return $url; 745} 746 747 748/** 749 * Indicate to build url with full path 750 * 751 * @param null 752 * @return null 753 */ 754function set_make_full_url() 755{ 756 global $page; 757 758 if (!isset($page['save_root_path'])) 759 { 760 if (isset($page['root_path'])) 761 { 762 $page['save_root_path']['path'] = $page['root_path']; 763 } 764 $page['save_root_path']['count'] = 1; 765 $page['root_path'] = get_absolute_root_url(); 766 } 767 else 768 { 769 $page['save_root_path']['count'] += 1; 770 } 771} 772 773/** 774 * Restore old parameter to build url with full path 775 * 776 * @param null 777 * @return null 778 */ 779function unset_make_full_url() 780{ 781 global $page; 782 783 if (isset($page['save_root_path'])) 784 { 785 if ($page['save_root_path']['count'] == 1) 786 { 787 if (isset($page['save_root_path']['path'])) 788 { 789 $page['root_path'] = $page['save_root_path']['path']; 790 } 791 else 792 { 793 unset($page['root_path']); 794 } 795 unset($page['save_root_path']); 796 } 797 else 798 { 799 $page['save_root_path']['count'] -= 1; 800 } 801 } 802} 803 804/** 805 * Embellish the url argument 806 * 807 * @param $url 808 * @return $url embellished 809 */ 810function embellish_url($url) 811{ 812 $url = str_replace('/./', '/', $url); 813 while ( ($dotdot = strpos($url, '/../', 1) ) !== false ) 814 { 815 $before = strrpos($url, '/', -(strlen($url)-$dotdot+1) ); 816 if ($before !== false) 817 { 818 $url = substr_replace($url, '', $before, $dotdot-$before+3); 819 } 820 else 821 break; 822 } 823 return $url; 824} 825 826/** 827 * Returns the 'home page' of this gallery 828 */ 829function get_gallery_home_url() 830{ 831 global $conf; 832 if (!empty($conf['gallery_url'])) 833 { 834 if (url_is_remote($conf['gallery_url']) or $conf['gallery_url'][0]=='/' ) 835 { 836 return $conf['gallery_url']; 837 } 838 return get_root_url().$conf['gallery_url']; 839 } 840 else 841 { 842 return make_index_url(); 843 } 844} 845 846/** 847 * returns $_SERVER['QUERY_STRING'] whithout keys given in parameters 848 * 849 * @param string[] $rejects 850 * @param boolean $escape escape *&* to *&* 851 * @returns string 852 */ 853function get_query_string_diff($rejects=array(), $escape=true) 854{ 855 if (empty($_SERVER['QUERY_STRING'])) 856 { 857 return ''; 858 } 859 860 parse_str($_SERVER['QUERY_STRING'], $vars); 861 862 $vars = array_diff_key($vars, array_flip($rejects)); 863 864 return '?' . http_build_query($vars, '', $escape ? '&' : '&'); 865} 866 867/** 868 * returns true if the url is absolute (begins with http) 869 * 870 * @param string $url 871 * @returns boolean 872 */ 873function url_is_remote($url) 874{ 875 if ( strncmp($url, 'http://', 7)==0 876 or strncmp($url, 'https://', 8)==0 ) 877 { 878 return true; 879 } 880 return false; 881} 882 883?> 884