xref: /web-php/error.php (revision faf6fae3)
1<?php
2/*
3
4 This script handles all 401, 403 and 404 error redirects,
5 and some directory requests (like /images). Uses the
6 preferred language setting and the REQUEST_URI to guess what
7 page should be displayed. In case there is no page that can
8 be displayed, the user is redirected to a search page.
9
10*/
11
12use phpweb\I18n\Languages;
13use phpweb\UserPreferences;
14
15// Ensure that our environment is set up
16include_once __DIR__ . '/include/prepend.inc';
17include_once __DIR__ . '/include/errors.inc';
18
19// Get URI for this request, strip leading slash
20// See langchooser.inc for more info on STRIPPED_URI
21$URI = substr($_SERVER['STRIPPED_URI'], 1);
22
23// ============================================================================
24// Mozilla Search Sidebar plugin resource file handling (need to be mirror
25// dependent, so the search results will show up in the sidebar)
26if ($URI == 'phpnetsearch.src') {
27    status_header(200);
28    include_once __DIR__ . '/include/mozsearch.inc';
29    exit;
30}
31// FIXME: Nuke the old firefox search plugin
32if ($URI == 'phpnetimprovedsearch.src') {
33    status_header(200);
34    include_once __DIR__ . '/include/mozopensearch.inc';
35    exit;
36}
37
38// ============================================================================
39// BC: handle bugs.php moved completely to bugs.php.net
40if (preg_match("!^bugs.php\\?(.+)$!", $URI, $array)) {
41    mirror_redirect("https://bugs.php.net/?$array[1]");
42}
43
44// ============================================================================
45// FC: handle advisories
46if (preg_match("!^security/advisories/PHPSA-(\\d+)\\.php$!", $URI, $array)) {
47    status_header(200);
48    $_GET["id"] = $array[1];
49    include_once __DIR__ . '/security/index.php';
50    exit;
51}
52
53// ============================================================================
54// Omit query string from URL and urldecode special chars
55$URI = urldecode(preg_replace("!(\\?.*$)!", "", $URI));
56
57// ============================================================================
58// An empty URI is useless at this point, so let's give them the search page
59if (empty($URI)) {
60    mirror_redirect("/search.php");
61}
62
63// ============================================================================
64// Perform a redirect for manual figures, other images display a 404 automatically
65if (preg_match("!^manual/(\\w+)/(print|printwn)/figures/(.+)$!", $URI, $parts)) {
66    mirror_redirect("/manual/$parts[1]/figures/$parts[3]");
67} elseif (preg_match("!\\.(pdf|gif|jpg|png)$!i", $URI)) {
68    error_404();
69}
70
71// ============================================================================
72// BC: handle .php3 files that were renamed to .php
73if (preg_match("!(.*\\.php)3$!", $URI, $array)) {
74    mirror_redirect("/$array[1]");
75}
76
77// ============================================================================
78// BC: handle moving english manual down into its own directory (also supports
79//     default language manual accessibility on mirror sites through /manual/filename)
80// @todo do we rely on this? how about removing it...
81if (preg_match("!^manual/([^/]*)$!", $URI, $array)) {
82    if (!isset(Languages::INACTIVE_ONLINE_LANGUAGES[$array[1]])) {
83        mirror_redirect("/manual/$LANG/$array[1]");
84    }
85} elseif (preg_match("!^manual/html/([^/]+)$!", $URI, $array)) {
86    $array[1] = preg_replace("!.html$!", ".php", $array[1]);
87    mirror_redirect("/manual/$LANG/$array[1]");
88}
89
90// ============================================================================
91// BC: News archive moved to subfolder
92if (preg_match("!^news-(\\d+)(\\.|$)!", $URI, $array)) {
93    mirror_redirect("/archive/$array[1].php");
94}
95
96// ============================================================================
97// BC: Release files moved to subfolder
98if (preg_match("!^release_([^\\.]+)(\\.php$|$)!", $URI, $array)) {
99    mirror_redirect("/releases/$array[1].php");
100}
101
102// ============================================================================
103// BC: Printer friendly manual page handling was separate previously, but we
104// only need to redirect the old URLs now. Our pages are now printer friendly
105// by design.
106if (preg_match("!^manual/(\\w+)/(print|printwn|html)((/.+)|$)!", $URI, $array)) {
107    $array[3] = preg_replace("!.html$!", ".php", $array[3]);
108    mirror_redirect("/manual/$array[1]$array[3]");
109}
110
111// ============================================================================
112// If someone is looking for something in distributions/* and it isn't there,
113// send them to the /releases page since that is likely to be most helpful.
114if (preg_match("!^distributions/.*!", $URI, $array)) {
115    status_header(404);
116    include_once __DIR__ . "/releases/index.php";
117}
118
119// ============================================================================
120// The trailing slash only causes problems from now on
121$URI = rtrim($URI, '/');
122
123// ============================================================================
124// Some nice URLs for getting something for download
125if (preg_match("!^get/([^/]+)$!", $URI, $what)) {
126    switch ($what[1]) {
127        case "php":
128            $URI = "downloads";
129            break;
130        case "docs": // intentional
131        case "documentation":
132            $URI = "download-docs";
133            break;
134    }
135}
136
137// ============================================================================
138// Nice URLs for download files, so wget works completely well with download links
139if (preg_match("!^get/([^/]+)/from/([^/]+)(/mirror)?$!", $URI, $dlinfo)) {
140
141    $df = $dlinfo[1];
142    if (strpos($df, "7-LATEST") !== false) {
143        include_once __DIR__ . "/include/version.inc";
144        [$latest] = release_get_latest();
145        $df = str_replace("7-LATEST", $latest, $df);
146    }
147
148    $mr = "https://www.php.net/";
149
150    // Check if that mirror really exists if not, bail out
151    if (!isset($MIRRORS[$mr])) {
152        error_nomirror($mr);
153        exit;
154    }
155
156    // Start the download process
157    include __DIR__ . "/include/do-download.inc";
158    $filename = get_actual_download_file($df);
159    if ($filename) {
160        status_header(200);
161        download_file($mr, $filename);
162    } else {
163        status_header(404);
164        /* The file didn't exist on this server.. ask the user to pick another mirror */
165        include __DIR__ . "/include/get-download.inc";
166    }
167    exit;
168}
169
170// php.net/42 --> likely a bug number
171if (is_numeric($URI)) {
172    mirror_redirect("http://bugs.php.net/bug.php?id=$URI");
173}
174
175// php.net/GH-123 -> php-src GH issue #123
176if (preg_match('/^GH-(\d+)$/', $URI, $matches)) {
177    mirror_redirect("https://github.com/php/php-src/issues/" . $matches[1]);
178}
179
180// php.net/supported-versions.PHP -> supported-versions.php
181if ($URI == 'supported-versions.PHP') {
182    mirror_redirect("https://www.php.net/supported-versions.php");
183}
184
185
186// ============================================================================
187// Redirect if the entered URI was a PHP page name (except some pages,
188// which we display in the mirror's language or the explicitly specified
189// language [see below])
190if (!in_array($URI, ['mirror-info', 'error', 'mod'], true) &&
191    file_exists($_SERVER['DOCUMENT_ROOT'] . "/$URI.php")) {
192    mirror_redirect("/$URI.php");
193}
194
195// Work with lowercased URI from now
196$URI = strtolower($URI);
197
198// Redirection hack, see error.inc for detailed description
199// These expect -foo not _foo
200$term = str_replace('_', '-', $URI);
201
202if ($path = is_known_ini($term)) {
203    status_header(301);
204    mirror_redirect("/manual/$LANG/$path");
205    exit;
206}
207if ($path = is_known_variable($term)) {
208    status_header(301);
209    mirror_redirect("/manual/$LANG/$path");
210    exit;
211}
212if ($path = is_known_term($term)) {
213    status_header(301);
214    mirror_redirect("/manual/$LANG/$path");
215    exit;
216}
217
218// ============================================================================
219// Major manual page modifications (need to handle shortcuts and pages in all languages)
220// Used permanent HTTP redirects, so search engines will be able to pick up the correct
221// new URLs for these pages.
222$manual_page_moves = [
223    // entry point changed
224    'installation' => 'install',
225
226    // was split among platforms (don't know where to redirect)
227    'install.apache' => 'install',
228    'install.apache2' => 'install',
229    'install.netscape-enterprise' => 'install',
230    'install.otherhttpd' => 'install',
231
232    // moved to platform sections
233    'install.caudium' => 'install.unix.caudium',
234    'install.commandline' => 'install.unix.commandline',
235    'install.fhttpd' => 'install.unix.fhttpd',
236    'install.hpux' => 'install.unix.hpux',
237    'install.iis' => 'install.windows.iis',
238    'install.linux' => 'install.unix',
239    'install.omnihttpd' => 'install.windows.omnihttpd',
240    'install.openbsd' => 'install.unix.openbsd',
241    'install.sambar' => 'install.windows.sambar',
242    'install.solaris' => 'install.unix.solaris',
243    'install.xitami' => 'install.windows.xitami',
244    'install.windows.installer.msi' => 'install.windows',
245    'install.windows.installer' => 'install.windows',
246
247    // Internals docs where moved
248    'zend' => 'internals2.ze1.zendapi',
249    'zend-api' => 'internals2.ze1.zendapi',
250    'internals.pdo' => 'internals2.pdo',
251    'phpdevel' => 'internals2.ze1.php3devel',
252    'tsrm' => 'internals2.ze1.tsrm',
253
254    // Replaced extensions
255    'aspell' => 'pspell',
256
257    // Refactored
258    'regexp.reference' => 'regexp.introduction',
259    "security" => "manual/security",
260
261    // MongoDB converted from set to book
262    'set.mongodb' => 'book.mongodb',
263    'mongodb.installation.homebrew' => 'mongodb.installation#mongodb.installation.homebrew',
264    'mongodb.installation.manual' => 'mongodb.installation#mongodb.installation.manual',
265    'mongodb.installation.pecl' => 'mongodb.installation#mongodb.installation.pecl',
266    'mongodb.installation.windows' => 'mongodb.installation#mongodb.installation.windows',
267    'mongodb.persistence.deserialization' => 'mongodb.persistence#mongodb.persistence.deserialization',
268    'mongodb.persistence.serialization' => 'mongodb.persistence#mongodb.persistence.serialization',
269];
270
271if (isset($manual_page_moves[$URI])) {
272    status_header(301);
273    mirror_redirect("/" . $manual_page_moves[$URI]);
274} elseif (preg_match("!^manual/([^/]+)/([^/]+).php$!", $URI, $match) &&
275          isset($manual_page_moves[$match[2]])) {
276    status_header(301);
277
278    $parts = explode('#', $manual_page_moves[$match[2]], 2);
279    if (count($parts) === 1) {
280        mirror_redirect("/manual/{$match[1]}/{$parts[0]}.php");
281    } else {
282        mirror_redirect("/manual/{$match[1]}/{$parts[0]}.php#{$parts[1]}");
283    }
284}
285
286$manual_redirections = [
287    'class.oci-lob' => 'class.ocilob',
288    'oci-lob.append' => 'ocilob.append',
289    'oci-lob.close' => 'ocilob.close',
290    'oci-lob.eof' => 'ocilob.eof',
291    'oci-lob.erase' => 'ocilob.erase',
292    'oci-lob.export' => 'ocilob.export',
293    'oci-lob.flush' => 'ocilob.flush',
294    'oci-lob.free' => 'ocilob.free',
295    'oci-lob.getbuffering' => 'ocilob.getbuffering',
296    'oci-lob.import' => 'ocilob.import',
297    'oci-lob.load' => 'ocilob.load',
298    'oci-lob.read' => 'ocilob.read',
299    'oci-lob.rewind' => 'ocilob.rewind',
300    'oci-lob.save' => 'ocilob.save',
301    'oci-lob.seek' => 'ocilob.seek',
302    'oci-lob.setbuffering' => 'ocilob.setbuffering',
303    'oci-lob.size' => 'ocilob.size',
304    'oci-lob.tell' => 'ocilob.tell',
305    'oci-lob.truncate' => 'ocilob.truncate',
306    'oci-lob.write' => 'ocilob.write',
307    'oci-lob.writetemporary' => 'ocilob.writetemporary',
308    'class.oci-collection' => 'class.ocicollection',
309    'oci-collection.append' => 'ocicollection.append',
310    'oci-collection.assign' => 'ocicollection.assign',
311    'oci-collection.assignelem' => 'ocicollection.assignelem',
312    'oci-collection.free' => 'ocicollection.free',
313    'oci-collection.getelem' => 'ocicollection.getelem',
314    'oci-collection.max' => 'ocicollection.max',
315    'oci-collection.size' => 'ocicollection.size',
316    'oci-collection.trim' => 'ocicollection.trim',
317    'splstack.setiteratormode' => 'spldoublylinkedlist.setiteratormode',
318    'splqueue.setiteratormode' => 'spldoublylinkedlist.setiteratormode',
319    'class.allow-dynamic-properties' => 'class.allowdynamicproperties',
320    'class.return-type-will-change' => 'class.returntypewillchange',
321    'class.sensitive-parameter' => 'class.sensitiveparameter',
322    'function.curl-file-create' => 'curlfile.construct',
323    'simplexmliterator.current' => 'simplexmlelement.current',
324    'simplexmliterator.getchildren' => 'simplexmlelement.getchildren',
325    'simplexmliterator.haschildren' => 'simplexmlelement.haschildren',
326    'simplexmliterator.key' => 'simplexmlelement.key',
327    'simplexmliterator.next' => 'simplexmlelement.next',
328    'simplexmliterator.rewind' => 'simplexmlelement.rewind',
329    'simplexmliterator.valid' => 'simplexmlelement.valid',
330];
331
332if (preg_match("!^manual/([^/]+)/([^/]+?)(?:\.php)?$!", $URI, $match) && isset($manual_redirections[$match[2]])) {
333    status_header(301);
334    mirror_redirect("/manual/$match[1]/" . $manual_redirections[$match[2]]);
335}
336
337// ============================================================================
338// Define shortcuts for PHP files, manual pages and external redirects
339$uri_aliases = [
340
341    # PHP page shortcuts
342    "download" => "downloads",
343    "getphp" => "downloads",
344    "getdocs" => "download-docs",
345    "documentation" => "docs",
346    "mailinglists" => "mailing-lists",
347    "mailinglist" => "mailing-lists",
348    "changelog" => "ChangeLog-8",
349    "gethelp" => "support",
350    "help" => "support",
351    "unsubscribe" => "unsub",
352    "subscribe" => "mailing-lists",
353    "logos" => "download-logos",
354
355    # manual shortcuts
356    "intro" => "introduction",
357    "whatis" => "introduction",
358    "whatisphp" => "introduction",
359    "what_is_php" => "introduction",
360
361    "windows" => "install.windows",
362    "win32" => "install.windows",
363
364    "globals" => "language.variables.predefined",
365    "register_globals" => "security.globals",
366    "registerglobals" => "security.globals",
367    "manual/en/security.registerglobals.php" => "security.globals", // fix for 4.3.8 configure
368    "magic_quotes" => "security.magicquotes",
369    "magicquotes" => "security.magicquotes",
370    "gd" => "image",
371    "bcmath" => "bc",
372    'streams' => 'book.stream',
373    "mongodb" => "book.mongodb",
374    "hrtime" => "function.hrtime", // Prefer function over PECL ext
375
376    "callback" => "language.pseudo-types",
377    "number" => "language.pseudo-types",
378    "mixed" => "language.pseudo-types",
379    "bool" => "language.types.boolean",
380    "boolean" => "language.types.boolean",
381    "int" => "language.types.integer",
382    "integer" => "language.types.integer",
383    "float" => "language.types.float",
384    "string" => "language.types.string",
385    "heredoc" => "language.types.string",
386    "<<<" => "language.types.string",
387    "object" => "language.types.object",
388    "null" => "language.types.null",
389    'callable' => 'language.types.callable',
390
391    "htaccess" => "configuration.changes",
392    "php_value" => "configuration.changes",
393
394    "ternary" => "language.operators.comparison",
395    "instanceof" => "language.operators.type",
396    "if" => "language.control-structures",
397    "static" => "language.variables.scope",
398    "global" => "language.variables.scope",
399    "@" => "language.operators.errorcontrol",
400    "&" => "language.references",
401    "**" => "language.operators.arithmetic",
402    "..." => "functions.arguments",
403    "splat" => "functions.arguments",
404    "arrow" => "functions.arrow",
405    "fn" => "functions.arrow",
406    // ?:, ??, ??=
407    // These shortcuts can not be captured here since they
408    // don't actually produce a 404 error.
409    // Instead, we have a small check in index.php directly.
410
411    "dowhile" => "control-structures.do.while",
412
413    "tut" => "tutorial",
414    "tut.php" => "tutorial", // BC
415
416    "faq.php" => "faq",      // BC
417    "bugs.php" => "bugs",     // BC
418    "bugstats.php" => "bugstats", // BC
419    "docs-echm.php" => "download-docs", // BC
420
421    "odbc" => "uodbc", // BC
422
423    "links" => "support", // BC
424    "links.php" => "support", // BC
425    "oracle" => "oci8",
426    "cli" => "features.commandline",
427
428    "oop" => "language.oop5",
429    "enum" => "language.enumerations",
430    "enums" => "language.enumerations",
431
432    "const" => "language.constants.syntax",
433    "class" => "language.oop5.basic",
434    "new" => "language.oop5.basic",
435    "extends" => "language.oop5.basic",
436    "clone" => "language.oop5.cloning",
437    "construct" => "language.oop5.decon",
438    "destruct" => "language.oop5.decon",
439    "public" => "language.oop5.visibility",
440    "private" => "language.oop5.visibility",
441    "protected" => "language.oop5.visibility",
442    "var" => "language.oop5.visibility",
443    "abstract" => "language.oop5.abstract",
444    "interface" => "language.oop5.interfaces",
445    "interfaces" => "language.oop5.interfaces",
446    "autoload" => "language.oop5.autoload",
447    "__autoload" => "language.oop5.autoload",
448    "language.oop5.reflection" => "book.reflection", // BC
449    "::" => "language.oop5.paamayim-nekudotayim",
450
451    "__construct" => "language.oop5.decon",
452    "__destruct" => "language.oop5.decon",
453    "__call" => "language.oop5.overloading",
454    "__callstatic" => "language.oop5.overloading",
455    "__get" => "language.oop5.overloading",
456    "__set" => "language.oop5.overloading",
457    "__isset" => "language.oop5.overloading",
458    "__unset" => "language.oop5.overloading",
459    "__sleep" => "language.oop5.magic",
460    "__wakeup" => "language.oop5.magic",
461    "__tostring" => "language.oop5.magic",
462    "__invoke" => "language.oop5.magic",
463    "__set_state" => "language.oop5.magic",
464    "__debuginfo" => "language.oop5.magic",
465    "__clone" => "language.oop5.cloning",
466
467    "throw" => "language.exceptions",
468    "try" => "language.exceptions",
469    "catch" => "language.exceptions",
470    "lsb" => "language.oop5.late-static-bindings",
471    "namespace" => "language.namespaces",
472    "use" => "language.namespaces.using",
473
474    "factory" => "language.oop5.patterns",
475    "singleton" => "language.oop5.patterns",
476
477    "trait" => "language.oop5.traits",
478    "traits" => "language.oop5.traits",
479
480    "news.php" => "archive/index", // BC
481    "readme.mirror" => "mirroring", // BC
482
483    "php5" => "language.oop5",
484    "zend_changes.txt" => "language.oop5", // BC
485    "zend2_example.phps" => "language.oop5", // BC
486    "zend_changes_php_5_0_0b2.txt" => "language.oop5", // BC
487    "zend-engine-2" => "language.oop5", // BC
488    "zend-engine-2.php" => "language.oop5", // BC
489
490    "news_php_5_0_0b2.txt" => "ChangeLog-5", // BC
491    "news_php_5_0_0b3.txt" => "ChangeLog-5", // BC
492
493    "manual/about-notes.php" => "manual/add-note",   // BC
494    "software/index.php" => "software",          // BC
495    "releases.php" => "releases/index",    // BC
496
497    "migration7" => "migration70",      // Consistent with migration5
498    "update_5_2.txt" => "migration52",      // BC
499    "readme_upgrade_51.php" => "migration51",      // BC
500    "internals" => "internals2",       // BC
501    "configuration.directives" => "ini.core",       // BC
502
503    # regexp. BC
504    "regexp.reference.backslash" => "regexp.reference.escape",
505    "regexp.reference.circudollar" => "regexp.reference.anchors",
506    "regexp.reference.squarebrackets" => "regexp.reference.character-classes",
507    "regexp.reference.verticalbar" => "regexp.reference.alternation",
508
509    # external shortcut aliases ;)
510    "dochowto" => "phpdochowto",
511
512    # CVS -> SVN
513    "anoncvs.php" => "git",
514    "cvs-php.php" => "git-php",
515
516    # SVN -> Git
517    "svn" => "git",
518    "svn.php" => "git",
519    "svn-php" => "git-php",
520    "svn-php.php" => "git-php",
521
522    # CVSUp -> Nada
523    "cvsup" => "mirroring",
524
525    # Other items
526    "security/crypt" => "security/crypt_blowfish",
527
528    # Bugfixes
529    "array_sort" => "sort", // #64743
530    "array-sort" => "sort", // #64743
531
532    # Removed pages
533    "tips.php" => "urlhowto",
534    "tips" => "urlhowto",
535];
536
537$external_redirects = [
538    "php4news" => "https://github.com/php/php-src/raw/PHP-4.4/NEWS",
539    "php5news" => "https://github.com/php/php-src/raw/PHP-5.6/NEWS",
540    "php53news" => "https://github.com/php/php-src/raw/PHP-5.3/NEWS",
541    "php54news" => "https://github.com/php/php-src/raw/PHP-5.4/NEWS",
542    "php55news" => "https://github.com/php/php-src/raw/PHP-5.5/NEWS",
543    "php56news" => "https://github.com/php/php-src/raw/PHP-5.6/NEWS",
544    "php70news" => "https://github.com/php/php-src/raw/PHP-7.0/NEWS",
545    "php71news" => "https://github.com/php/php-src/raw/PHP-7.1/NEWS",
546    "php72news" => "https://github.com/php/php-src/raw/PHP-7.2/NEWS",
547    "php73news" => "https://github.com/php/php-src/raw/PHP-7.3/NEWS",
548    "php74news" => "https://github.com/php/php-src/raw/PHP-7.4/NEWS",
549    "php80news" => "https://github.com/php/php-src/raw/PHP-8.0/NEWS",
550    "phptrunknews" => "https://github.com/php/php-src/raw/master/NEWS",
551    "pear" => "http://pear.php.net/",
552    "bugs" => "https://bugs.php.net/",
553    "bugstats" => "https://bugs.php.net/stats.php",
554    "phpdochowto" => "https://doc.php.net/guide/",
555    "rev" => "https://doc.php.net/revcheck.php?p=graph&lang=$LANG",
556    "release/5_3_0.php" => "/releases/5_3_0.php", // PHP 5.3.0 release announcement had a typo
557    "ideas.php" => "http://wiki.php.net/ideas", // BC
558    "releases.atom" => "/releases/feed.php", // BC, No need to pre-generate it
559    "spec" => "https://github.com/php/php-langspec",
560    "sunglasses" => "https://www.youtube.com/watch?v=dQw4w9WgXcQ", // Temporary easter egg for bug#66144
561];
562
563// Temporary hack to fix bug #49956 for mysqli -- Please don't hate me for this. Data taken from mysqli/summary.xml
564$mysqli_redirects = [
565    "mysqli_affected_rows" => "mysqli.affected-rows",
566    "mysqli_get_client_version" => "mysqli.client-version",
567    "mysqli_connect_errno" => "mysqli.connect-errno",
568    "mysqli_connect_error" => "mysqli.connect-error",
569    "mysqli_errno" => "mysqli.errno",
570    "mysqli_error" => "mysqli.error",
571    "mysqli_field_count" => "mysqli.field-count",
572    "mysqli_get_host_info" => "mysqli.host-info",
573    "mysqli_get_proto_info" => "mysqli.protocol-version",
574    "mysqli_get_server_version" => "mysqli.server-version",
575    "mysqli_info" => "mysqli.info",
576    "mysqli_insert_id" => "mysqli.insert-id",
577    "mysqli_sqlstate" => "mysqli.sqlstate",
578    "mysqli_warning_count" => "mysqli.warning-count",
579    "mysqli_autocommit" => "mysqli.autocommit",
580    "mysqli_change_user" => "mysqli.change-user",
581    "mysqli_character_set_name" => "mysqli.character-set-name",
582    "mysqli_close" => "mysqli.close",
583    "mysqli_commit" => "mysqli.commit",
584    "mysqli_connect" => "mysqli.construct",
585    "mysqli_debug" => "mysqli.debug",
586    "mysqli_dump_debug_info" => "mysqli.dump-debug-info",
587    "mysqli_get_charset" => "mysqli.get-charset",
588    "mysqli_get_connection_stats" => "mysqli.get-connection-stats",
589    "mysqli_get_client_info" => "mysqli.get-client-info",
590    "mysqli_get_client_stats" => "mysqli.get-client-stats",
591    "mysqli_get_cache_stats" => "mysqli.get-cache-stats",
592    "mysqli_get_server_info" => "mysqli.get-server-info",
593    "mysqli_get_warnings" => "mysqli.get-warnings",
594    "mysqli_init" => "mysqli.init",
595    "mysqli_kill" => "mysqli.kill",
596    "mysqli_more_results" => "mysqli.more-results",
597    "mysqli_multi_query" => "mysqli.multi-query",
598    "mysqli_next_result" => "mysqli.next-result",
599    "mysqli_options" => "mysqli.options",
600    "mysqli_ping" => "mysqli.ping",
601    "mysqli_prepare" => "mysqli.prepare",
602    "mysqli_query" => "mysqli.query",
603    "mysqli_real_connect" => "mysqli.real-connect",
604    "mysqli_real_escape_string" => "mysqli.real-escape-string",
605    "mysqli_real_query" => "mysqli.real-query",
606    "mysqli_refresh" => "mysqli.refresh",
607    "mysqli_rollback" => "mysqli.rollback",
608    "mysqli_select_db" => "mysqli.select-db",
609    "mysqli_set_charset" => "mysqli.set-charset",
610    "mysqli_set_local_infile_default" => "mysqli.set-local-infile-default",
611    "mysqli_set_local_infile_handler" => "mysqli.set-local-infile-handler",
612    "mysqli_ssl_set" => "mysqli.ssl-set",
613    "mysqli_stat" => "mysqli.stat",
614    "mysqli_stmt_init" => "mysqli.stmt-init",
615    "mysqli_store_result" => "mysqli.store-result",
616    "mysqli_thread_id" => "mysqli.thread-id",
617    "mysqli_thread_safe" => "mysqli.thread-safe",
618    "mysqli_use_result" => "mysqli.use-result",
619    "mysqli_stmt_affected_rows" => "mysqli-stmt.affected-rows",
620    "mysqli_stmt_errno" => "mysqli-stmt.errno",
621    "mysqli_stmt_error" => "mysqli-stmt.error",
622    "mysqli_stmt_field_count" => "mysqli-stmt.field-count",
623    "mysqli_stmt_insert_id" => "mysqli-stmt.insert-id",
624    "mysqli_stmt_param_count" => "mysqli-stmt.param-count",
625    "mysqli_stmt_sqlstate" => "mysqli-stmt.sqlstate",
626    "mysqli_stmt_attr_get" => "mysqli-stmt.attr-get",
627    "mysqli_stmt_attr_set" => "mysqli-stmt.attr-set",
628    "mysqli_stmt_bind_param" => "mysqli-stmt.bind-param",
629    "mysqli_stmt_bind_result" => "mysqli-stmt.bind-result",
630    "mysqli_stmt_close" => "mysqli-stmt.close",
631    "mysqli_stmt_data_seek" => "mysqli-stmt.data-seek",
632    "mysqli_stmt_execute" => "mysqli-stmt.execute",
633    "mysqli_stmt_fetch" => "mysqli-stmt.fetch",
634    "mysqli_stmt_free_result" => "mysqli-stmt.free-result",
635    "mysqli_stmt_get_result" => "mysqli-stmt.get-result",
636    "mysqli_stmt_get_warnings" => "mysqli-stmt.get-warnings",
637    "mysqli_stmt_more_results" => "mysqli-stmt.more-results",
638    "mysqli_stmt_next_result" => "mysqli-stmt.next-result",
639    "mysqli_stmt_num_rows" => "mysqli-stmt.num-rows",
640    "mysqli_stmt_prepare" => "mysqli-stmt.prepare",
641    "mysqli_stmt_reset" => "mysqli-stmt.reset",
642    "mysqli_stmt_result_metadata" => "mysqli-stmt.result-metadata",
643    "mysqli_stmt_send_long_data" => "mysqli-stmt.send-long-data",
644    "mysqli_stmt_store_result" => "mysqli-stmt.store-result",
645    "mysqli_field_tell" => "mysqli-result.current-field",
646    "mysqli_num_fields" => "mysqli-result.field-count",
647    "mysqli_fetch_lengths" => "mysqli-result.lengths",
648    "mysqli_num_rows" => "mysqli-result.num-rows",
649    "mysqli_data_seek" => "mysqli-result.data-seek",
650    "mysqli_fetch_all" => "mysqli-result.fetch-all",
651    "mysqli_fetch_array" => "mysqli-result.fetch-array",
652    "mysqli_fetch_assoc" => "mysqli-result.fetch-assoc",
653    "mysqli_fetch_field_direct" => "mysqli-result.fetch-field-direct",
654    "mysqli_fetch_field" => "mysqli-result.fetch-field",
655    "mysqli_fetch_fields" => "mysqli-result.fetch-fields",
656    "mysqli_fetch_object" => "mysqli-result.fetch-object",
657    "mysqli_fetch_row" => "mysqli-result.fetch-row",
658    "mysqli_field_seek" => "mysqli-result.field-seek",
659    "mysqli_free_result" => "mysqli-result.free",
660    "mysqli_embedded_server_end" => "mysqli-driver.embedded-server-end",
661    "mysqli_embedded_server_start" => "mysqli-driver.embedded-server-start",
662];
663
664// Merge this temporary hack with $uri_aliases so it'll be treated as such
665$uri_aliases = array_merge($uri_aliases, $mysqli_redirects);
666
667// ============================================================================
668// "Rewrite" the URL, if it was a shortcut
669
670if (isset($uri_aliases[$URI])) {
671    $URI = $uri_aliases[$URI];
672    /* If it was a page alias, redirect right away */
673    if (file_exists($_SERVER['DOCUMENT_ROOT'] . "/$URI.php")) {
674        mirror_redirect("/$URI.php");
675    }
676}
677
678// ============================================================================
679// Execute external redirect if a rule exists for the URI
680if (isset($external_redirects[$URI])) {
681    mirror_redirect($external_redirects[$URI]);
682}
683
684// Temporary hack for mirror-info, until all the pages
685// will be capable of being included from anywhere
686if ($URI == 'mirror-info') {
687    status_header(200);
688    include_once __DIR__ . "/$URI.php";
689    exit;
690}
691
692// ============================================================================
693// Try to find the page using the preferred language as a manual page
694include_once __DIR__ . "/include/manual-lookup.inc";
695$try = find_manual_page($LANG, $URI);
696if ($try) {
697    status_header(200);
698    include_once __DIR__ . $try;
699    exit;
700}
701// BC. The class methods are now classname.methodname
702if (preg_match("!^manual/(.+)/function\.(.+)-(.+).php$!", $URI, $array)) {
703    $try = find_manual_page($array[1], $array[2] . "." . $array[3]);
704    if ($try) {
705        status_header(301);
706        mirror_redirect($try);
707        exit;
708    }
709}
710
711// ============================================================================
712// For manual pages for inactive languages, point visitors to the English page
713if (preg_match("!^manual/([^/]+)/([^/]+).php$!", $URI, $match) &&
714    isset(Languages::INACTIVE_ONLINE_LANGUAGES[$match[1]])) {
715    $try = find_manual_page("en", $match[2]);
716    if ($try) {
717        error_inactive_manual_page(Languages::INACTIVE_ONLINE_LANGUAGES[$match[1]], $try);
718    }
719}
720
721// ============================================================================
722// 404 page for manual pages (eg. not built language)
723if (strpos($URI, "manual/") === 0) {
724    $legacy_manual_urls = get_legacy_manual_urls($URI);
725    if (count($legacy_manual_urls) > 0) {
726        fallback_to_legacy_manuals($legacy_manual_urls);
727    }
728    error_404_manual();
729}
730
731// ============================================================================
732// If no match was found till this point, the last action is to start a
733// search with the URI the user typed in
734$fallback = ($userPreferences->searchType === UserPreferences::URL_MANUAL ? "404manual" : "404quickref");
735mirror_redirect(
736    '/search.php?show=' . $fallback . '&lang=' . urlencode($LANG) .
737    '&pattern=' . substr($_SERVER['REQUEST_URI'], 1),
738);
739