PHP_SELF contre PATH_INFO contre SCRIPT_NAME contre REQUEST_URI

105

Je construis une application PHP dans CodeIgniter. CodeIgniter envoie toutes les demandes au contrôleur principal: index.php. Cependant, je n'aime pas voir index.phpdans l'URI. Par exemple, http://www.example.com/faq/whateveracheminera vers http://www.example.com/index.php/faq/whatever. J'ai besoin d'un moyen fiable pour qu'un script sache quelle est son adresse, afin qu'il sache quoi faire avec la navigation. J'ai utilisé mod_rewrite, selon la documentation de CodeIgniter.

La règle est la suivante:

RewriteEngine on
RewriteCond $1 !^(images|inc|favicon\.ico|index\.php|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L] 

Normalement, je vérifierais simplement php_self, mais dans ce cas, c'est toujours index.php. Je peux l'obtenir de REQUEST_URI, PATH_INFOetc., mais j'essaie de décider laquelle sera la plus fiable. Ne sait quiconque (ou savoir où trouver) la vraie différence entre PHP_SELF, PATH_INFO, SCRIPT_NAMEet REQUEST_URI? Merci de votre aide!

Remarque : j'ai dû ajouter des espaces, car SO voit le trait de soulignement et le met en italique pour une raison quelconque.

Mise à jour : correction des espaces.

Eli
la source

Réponses:

50

La documentation PHP peut vous faire la différence:

"PHP_SELF"

Le nom de fichier du script en cours d'exécution, par rapport à la racine du document. Par exemple, $ _SERVER ['PHP_SELF'] dans un script à l'adresse http://example.com/test.php/foo.bar serait /test.php/foo.bar . La constante __FILE__ contient le chemin complet et le nom de fichier du fichier actuel (c'est-à-dire inclus). Si PHP fonctionne en tant que processeur de ligne de commande, cette variable contient le nom du script depuis PHP 4.3.0. Auparavant, il n'était pas disponible.

«SCRIPT_NAME»

Contient le chemin du script actuel. Ceci est utile pour les pages qui doivent pointer vers elles-mêmes. La constante __FILE__ contient le chemin complet et le nom de fichier du fichier actuel (c'est-à-dire inclus).

«REQUEST_URI»

L'URI qui a été donnée pour accéder à cette page; par exemple, «/index.html» .

PATH_INFO ne semble pas être documenté ...

Jeremy Ruten
la source
3
Il ne s'agit probablement pas de la documentation PHP mais du CGI :) Et là PATH_INFO est documenté: tools.ietf.org/html/rfc3875#section-4 Mais il y a des problèmes connus qu'Apache et nginx ne donnent pas toujours cette variable.
SimonSimCity
1
La réponse d'Odin ci-dessous ajoute des explications utiles qui sont complétées par des exemples. J'ai du mal à comprendre ce que ces variables représentent dans un contexte général avec un path_info, une chaîne de requête, une redirection, des alias, sur différents systèmes d'exploitation, de CLI vs SERVER, etc.
4
-1 Juste pour expliquer pourquoi j'ai voté contre: la raison pour laquelle je suis venu à ce poste est que la documentation n'est pas claire. La réponse d'Odin ci-dessous fournit une explication claire des différences entre ces variables. Je pense que c'est une réponse insuffisante pour simplement copier et coller facilement trouvé mais aussi une documentation insuffisante. Je pense que la plupart des gens auraient déjà dû visiter la documentation pour même connaître la liste des éléments de la variable $ _SERVER mentionnée ci-dessus.
dallin
230

Quelques exemples pratiques des différences entre ces variables:
Exemple 1. PHP_SELF est différent de SCRIPT_NAME uniquement lorsque l'url demandée est au format :
http://example.com/test.php/foo/bar

[PHP_SELF] => /test.php/foo/bar
[SCRIPT_NAME] => /test.php

(cela semble être le seul cas où PATH_INFO contient des informations sensibles [PATH_INFO] => / foo / bar) Remarque: cela était différent dans certaines anciennes versions de PHP (<= 5.0?).

Exemple 2. REQUEST_URI est différent de SCRIPT_NAME lorsqu'une chaîne de requête non vide est saisie:
http://example.com/test.php?foo=bar

[SCRIPT_NAME] => /test.php
[REQUEST_URI] => /test.php?foo=bar

Exemple 3. REQUEST_URI est différent de SCRIPT_NAME lorsque la redirection côté serveur est en vigueur (par exemple mod_rewrite sur apache):

http://example.com/test.php

[REQUEST_URI] => /test.php
[SCRIPT_NAME] => /test2.php

Exemple 4. REQUEST_URI est différent de SCRIPT_NAME lors de la gestion des erreurs HTTP avec des scripts.
Utilisation de la directive Apache ErrorDocument 404 /404error.php
http://example.com/test.php

[REQUEST_URI] => /test.php
[SCRIPT_NAME] => /404error.php

Sur le serveur IIS utilisant des pages d'erreur personnalisées
http://example.com/test.php

[SCRIPT_NAME] => /404error.php
[REQUEST_URI] => /404error.php?404;http://example.com/test.php
Odin
la source
21
+1, "Un exemple n'est pas un moyen d'apprendre, c'est le seul moyen d'apprendre." - Je dois toujours revérifier ce truc, très belle recherche sur les erreurs 404. =)
Alix Axel
16
+1: 1ère fois de ma vie, j'ai compris la différence. Ils devraient mettre à jour la documentation PHP avec votre réponse
Marco Demaio
Exemple1: [SCRIPT_NAME] => /test.php/ Il ne devrait pas y avoir de "/" à la fin: Exemple1: [SCRIPT_NAME] => /test.php Quoi qu'il en soit, c'est ce que je vois en PHP 5.3.6. Bons exemples.
Dawid Ohia
Vous avez raison JohnM2, j'ai maintenant vérifié PHP 5.4 et le résultat pour l'URL /pinfo.php/first/second?third=fourth est le suivant: QUERY_STRING => troisième = quatrième REQUEST_URI => /pinfo.php/first/second ? troisième = quatrième SCRIPT_NAME => /pinfo.php PATH_INFO => / premier / deuxième
Odin
J'ai également testé cela sur 5.2.17 et il n'y a pas /à la fin du SCRIPT_NAME. Cela semble être cohérent dans PHP 5.2-5.4 alors, en envisageant de modifier la réponse pour refléter cela.
Fabrício Matté
24

PATH_INFO n'est disponible que lors de l'utilisation de htaccess comme ceci:

Exemple 1

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(.*)$ index.php/$1 [L]

Reste le même

[SCRIPT_NAME] => /index.php

Racine

http://domain.com/

[PHP_SELF]     => /index.php
[PATH_INFO] IS NOT AVAILABLE (fallback to REQUEST_URI in your script)
[REQUEST_URI]  => /
[QUERY_STRING] => 

Chemin

http://domain.com/test

[PHP_SELF]     => /index.php/test
[PATH_INFO]    => /test
[REQUEST_URI]  => /test
[QUERY_STRING] => 

Chaîne de requête

http://domain.com/test?123

[PHP_SELF]     => /index.php/test
[PATH_INFO]    => /test
[REQUEST_URI]  => /test?123
[QUERY_STRING] => 123

Exemple 2

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(.*)$ index.php?url=$1 [L,QSA]

Reste le même

[SCRIPT_NAME]  => /index.php
[PHP_SELF]     => /index.php
[PATH_INFO] IS NOT AVAILABLE (fallback to REQUEST_URI in your script)

Racine

http://domain.com/

[REQUEST_URI]  => /
[QUERY_STRING] => 

Chemin

http://domain.com/test

[REQUEST_URI]  => /test
[QUERY_STRING] => url=test

Chaîne de requête

http://domain.com/test?123

[REQUEST_URI]  => /test?123
[QUERY_STRING] => url=test&123

Exemple 3

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(([a-z]{2})|(([a-z]{2})/)?(.*))$ index.php/$5 [NC,L,E=LANGUAGE:$2$4]

ou

RewriteRule ^([a-z]{2})(/(.*))?$ $3 [NC,L,E=LANGUAGE:$1]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(.*)$ index.php/$1 [L]

Reste le même

[SCRIPT_NAME] => /index.php

Racine

http://domain.com/

[PHP_SELF]          => /index.php
[PATH_INFO] IS NOT AVAILABLE (fallback to REQUEST_URI in your script)
[REQUEST_URI]       => /
[QUERY_STRING]      => 
[REDIRECT_LANGUAGE] IS NOT AVAILABLE

Chemin

http://domain.com/test

[PHP_SELF]          => /index.php/test
[PATH_INFO]         => /test
[REQUEST_URI]       => /test
[QUERY_STRING]      => 
[REDIRECT_LANGUAGE] => 

Langue

http://domain.com/en

[PHP_SELF]          => /index.php/
[PATH_INFO]         => /
[REQUEST_URI]       => /en
[QUERY_STRING]      => 
[REDIRECT_LANGUAGE] => en

Chemin de langue

http://domain.com/en/test

[PHP_SELF]          => /index.php/test
[PATH_INFO]         => /test
[REQUEST_URI]       => /en/test
[REDIRECT_LANGUAGE] => en

Chaîne de requête de langue

http://domain.com/en/test?123

[PHP_SELF]          => /index.php/test
[PATH_INFO]         => /test
[REQUEST_URI]       => /en/test?123
[QUERY_STRING]      => 123
[REDIRECT_LANGUAGE] => en
Mike
la source
C'était génial. Merci de votre aide!
Gabriel Fair
1
Cette réponse est écrite d'une manière qui suggère que seule la réécriture d'URL peut créer un path_info, mais, bien sûr, les informations de chemin peuvent être entrées directement dans l'URL d'origine.
12

Chemins PHP

    $_SERVER['REQUEST_URI']    = Chemin Web, URI demandé
    $_SERVER['PHP_SELF']    = chemin Web, fichier demandé + info de chemin
    $_SERVER['SCRIPT_NAME']    = chemin Web, fichier demandé
    $_SERVER['SCRIPT_FILENAME']   = chemin du fichier, fichier demandé
    __FILE__    = chemin du fichier, fichier actuel

  • Le chemin du fichier est un chemin de fichier système comme /var/www/index.php, après la résolution d'alias
  • Le chemin Web est un chemin de document serveur comme à /index.phppartir de http://foo.com/index.php, et peut même ne correspondre à aucun fichier
  • Le fichier actuel désigne le fichier de script inclus , pas tout script qui l'inclut
  • Le fichier demandé signifie le fichier de script d'inclusion , pas celui inclus
  • URI est la requête HTTP comme /index.php?foo=bar, avant toute réécriture d'URL
  • Les informations de chemin sont toutes les données Apache supplémentaires situées après le nom du script mais avant la chaîne de requête

Ordre de fonctionnement

  1. Le client envoie au serveur une requête HTTP REQUEST_URI
  2. Le serveur effectue toute réécriture d'URL à partir de fichiers .htaccess, etc. pour obtenirPHP_SELF
  3. Le serveur se sépare PHP_SELFen SCRIPT_FILENAME+PATH_INFO
  4. Le serveur exécute la résolution d'alias et convertit le chemin d'URL complet en chemin de fichier système pour obtenirSCRIPT_FILENAME
  5. Le fichier de script résultant peut en inclure d'autres, où se __FILE__réfère au chemin d'accès au fichier actuel
Beejor
la source
C'est bon. Voici mes commentaires. Premièrement, $ _SERVER ['SCRIPT_NAME'] et $ _SERVER ['SCRIPT_FILENAME'] sont le nom du script, sauf que le dernier est après l'exécution des alias. Deuxièmement, $ _SERVER ['PHP_SELF'] n'est pas le script, mais le script + les informations de chemin. Encore une fois, $ _SERVER ['SCRIPT_NAME'] est le script (avant les alias). Enfin, il est utile de savoir à quel stade, après ou avant les règles de réécriture, après ou avant les alias, ces variables sont définies. Voyez ma réponse.
@ Dominic108 J'ai révisé ma réponse en fonction de vos suggestions, j'ai un peu arrangé les choses et ajouté une section Ordre des opérations. Laissez-moi savoir ce que vous pensez. Merci!
Beejor
Dans votre commande, vous devez permuter $_SERVER['SCRIPT_NAME']et   $_SERVER['PHP_SELF'], parce que mod_rewrite crée le chemin complet, qui est $_SERVER['PHP_SELF']. La séparation se produit ensuite. Notez que les alias prennent également en compte le chemin complet pour définir le nom de fichier du script, mais la séparation qui a défini le nom du script et le chemin_info a déjà eu lieu, donc ils ne seront pas affectés.
@ Dominic108 J'ai de nouveau révisé ma réponse. Pour une raison quelconque, votre proposition de modification a été rejetée, mais pour autant que je sache, vous avez raison de dire que deux de mes articles étaient en panne. Je ne suis pas aussi familier avec les alias, donc je compte sur votre expertise pour cette partie. Merci encore!
Beejor
5

Vous pouvez consulter la classe URI et utiliser $ this-> uri-> uri_string ()

Renvoie une chaîne avec l'URI complet.

Par exemple, s'il s'agit de votre URL complète:

http://example.com/index.php/news/local/345

La fonction renverrait ceci:

/news/local/345

Ou vous pouvez utiliser les segments pour explorer des zones spécifiques sans avoir à trouver des valeurs d'analyse / regex

Adam
la source
Merci - c'est une bonne idée, mais je les utilise dans un hook pré-système qui devra être exécuté avant que le contrôleur ne soit opérationnel.
Eli
4

Personnellement, j'utilise le $REQUEST_URIcar il fait référence à l'URI entré et non à l'emplacement sur le disque du serveur.

Xenph Yan
la source
Est-ce toujours l'URI complet?
Eli
En règle générale, vous pouvez rencontrer des problèmes avec Apache sous Windows, mais ce n'est que pour les URI qui ne résolvent pas.
Xenph Yan
4

Il y a très peu à ajouter à la réponse d'Odin. J'ai juste eu envie de fournir un exemple complet de la requête HTTP au fichier réel sur le système de fichiers pour illustrer les effets de la réécriture d'URL et des alias. Sur le système de fichiers, le script /var/www/test/php/script.phpest

<?php
include ("script_included.php")
?>

/var/www/test/php/script_included.phpest

<?php
echo "REQUEST_URI: " .  $_SERVER['REQUEST_URI'] . "<br>"; 
echo "PHP_SELF: " .  $_SERVER['PHP_SELF'] . "<br>";
echo "QUERY_STRING: " .  $_SERVER['QUERY_STRING'] . "<br>";
echo "SCRIPT_NAME: " .  $_SERVER['SCRIPT_NAME'] . "<br>";
echo "PATH_INFO: " .  $_SERVER['PATH_INFO'] . "<br>";
echo "SCRIPT_FILENAME: " . $_SERVER['SCRIPT_FILENAME'] . "<br>";
echo "__FILE__ : " . __FILE__ . "<br>";  
?>

et /var/www/test/.htaccess est

RewriteEngine On
RewriteRule before_rewrite/script.php/path/(.*) after_rewrite/script.php/path/$1 

et le fichier de configuration Apache inclut l'alias

Alias /test/after_rewrite/ /var/www/test/php/

et la requête http est

www.example.com/test/before_rewrite/script.php/path/info?q=helloword

La sortie sera

REQUEST_URI: /test/before_rewrite/script.php/path/info?q=helloword
PHP_SELF: /test/after_rewrite/script.php/path/info
QUERY_STRING: q=helloword
SCRIPT_NAME: /test/after_rewrite/script.php
PATH_INFO: /path/info
SCRIPT_FILENAME: /var/www/test/php/script.php
__FILE__ : /var/www/test/php/script_included.php

Ce qui suit est toujours valable

PHP_SELF = SCRIPT_NAME + PATH_INFO = full url path between domain and query string. 

S'il n'y a pas de réécriture de mod_rewrite, mod_dir, ErrorDocument ou toute forme de réécriture d'URL, nous avons également

REQUEST_URI = PHP_SELF + ? + QUERY_STRING 

Les alias affectent les chemins des fichiers système SCRIPT_FILENAMEet __FILE__non les chemins URL, qui sont définis auparavant - voir les exceptions ci-dessous. Les alias peuvent utiliser le chemin d'URL complet, y compris PATH_INFO. Il ne pourrait y avoir aucun lien entre SCRIPT_NAMEet SCRIPT_FILENAME.

Il n'est pas tout à fait exact que les alias ne soient pas résolus au moment où le chemin de l'URL [PHP_SELF] = [SCRIPT_NAME] + [PATH_INFO] est défini, car les alias sont considérés pour rechercher le système de fichiers et nous savons à partir de l'exemple 4 de la réponse d'Odin que le système de fichiers est recherché pour déterminer si le fichier existe, mais cela n'est pertinent que lorsque le fichier n'est pas trouvé. De même, mod_dir appelle mod_alias pour rechercher dans le système de fichiers, mais cela n'est pertinent que si vous avez un alias tel que Alias \index.php \var\www\index.phpet que l'URI de la requête est un répertoire.


la source
Salut Dominic108, merci pour la révision. Je pense qu'il est utile d'inclure les informations de réécriture. Pour moi, c'était implicite, mais pour d'autres, ce n'est peut-être pas aussi intuitif.
Beejor
1

Si jamais vous oubliez quelles variables font quoi, vous pouvez écrire un petit script qui utilise phpinfo () et l'appeler depuis une URL avec une chaîne de requête. Étant donné que les installations de logiciels de serveur présentent les variables renvoyées par PHP, il est toujours judicieux de vérifier la sortie de la machine au cas où les réécritures dans le fichier de configuration du serveur entraînent des résultats différents de ceux attendus. Enregistrez-le sous quelque chose comme _inf0.php:

<?php
    $my_ip = '0.0.0.0';

   if($_SERVER['REMOTE_ADDR']==$my_ip){
     phpinfo();
   } else {
     //something
   }

Alors tu appellerais /_inf0.php?q=500

Zéro absolu
la source
-1

Sauvegardez une seconde, vous avez d'abord adopté la mauvaise approche. Pourquoi ne pas faire ça

RewriteEngine on
RewriteCond $1 !^(images|inc|favicon\.ico|index\.php|robots\.txt)
RewriteRule ^(.*)$ /index.php?url=$1 [L]

au lieu? Puis attrape-le avec$_GET['url'];

Kate Gregory
la source
Pourquoi réinventer la roue? Ces données sont beaucoup plus facilement accessibles!
Kenneth
Et il y a une complexité supplémentaire si la demande d'origine doit avoir une chaîne de requête. Dans son état actuel, le code ci-dessus écrasera simplement la chaîne de requête. Si vous fusionnez des chaînes de requête ( QSAindicateur), les paramètres de chaîne de requête peuvent potentiellement être écrasés (par exemple, si vous aviez besoin d'un urlparamètre lors de la requête initiale) ou pire, être vulnérables aux attaques XSS.
MrWhite