Sur Internet, y compris même ici dans Stack Overflow, les utilisateurs affirment qu’un bon moyen de vérifier si une demande est AJAX ou non est la suivante:
if (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest' ) {...}
Cependant, je ne vois pas $_SERVER['HTTP_X_REQUESTED_WITH']
dans la documentation officielle PHP
Et quand j'essaie de faire ce qui suit:
echo $_SERVER['HTTP_X_REQUESTED_WITH'];
Rien n'est sorti.
Est-ce que je fais quelque chose de mal? Parce que j'aimerais vraiment pouvoir utiliser $_SERVER['HTTP_X_REQUESTED_WITH']
s'il est disponible.
Les variables dans $_SERVER
ne font pas vraiment partie de PHP, c'est pourquoi vous ne les trouverez pas dans la documentation PHP. Ils sont préparés par le serveur Web qui les transmet au langage de script.
Autant que je sache, le X-Requested-With
est envoyé par les fonctions Ajax de la plupart des principaux frameworks, mais pas tous (Dojo, par exemple, l'a ajouté il y a seulement deux ans: # 5801 ). En tant que tel, et en prenant en compte les commentaires de @bobince ', il est prudent de dire que ce n'est généralement pas une méthode fiable à 100% pour déterminer si une requête est une requête AJAX ou non.
La seule méthode 100% sécurisée consiste à envoyer un indicateur prédéfini (par exemple, une variable GET) avec la demande et à la page de réception de vérifier la présence de cet indicateur.
n'oubliez pas que vous pouvez facilement usurper n'importe quel en-tête avec cURL comme si
curl_setopt($ch,CURLOPT_HTTPHEADER,array("X-Requested-With : XMLHttpRequest"));
Les clés $_SERVER
qui commencent par HTTP_
sont générées à partir des en-têtes de requête HTTP. Dans ce cas, l'en-tête X-Requested-With
.
Cet en-tête est une normalisation en cours de toutes les bibliothèques AJAX.
Cela ne sera pas documenté dans la documentation php proprement dite, mais plutôt dans les différentes bibliothèques AJAX qui définissent cet en-tête. Les bibliothèques communes ont envoyé cet en-tête: jQuery, Mojo, Prototype, ...
Habituellement, ces bibliothèques définissent l’en-tête en utilisant
xhrobj.setRequestHeader("X-Requested-With", "XMLHttpRequest");
Voici une fonction rapide avec un exemple d'utilisation:
function isXmlHttpRequest()
{
$header = isset($_SERVER['HTTP_X_REQUESTED_WITH']) ? $_SERVER['HTTP_X_REQUESTED_WITH'] : null;
return ($header === 'XMLHttpRequest');
}
// example - checking our active call
if(!isXmlHttpRequest())
{
echo 'Not an ajax request';
}
else
{
echo 'is an ajax request';
}
echo $_SERVER['HTTP_X_REQUESTED_WITH'];
Qu'attendiez-vous d'un tel code? Supposons que vous l'exécutez directement à partir du navigateur, sans utiliser la demande AJAX. Alors, comment se fait-il que cet en-tête puisse être défini?
Eh bien, la réponse à la question ultime de la vie, de l’univers et de tout: un renifleur HTTP! Procurez-vous-en un et oubliez d’imprimer la variable $ _SERVER.
Firebug en a un, ou vous pouvez utiliser le proxy HTTP Fiddler ou le plugin LiveHTTPHeaders Mozilla. Je m'ennuie de faire des liens mais ça googlé facilement.
Donc, avec HTTP sniffer, vous pouvez être sûr de n’importe quel en-tête HTTP.
Notez que vous ne pouvez empêcher aucun "accès direct" en utilisant XHR, car chaque requête HTTP adressée à votre serveur est déjà "directe".
Vous pouvez aussi blâmer certains bugs de votre navigateur - voir cette question et sa solution pour Firefox
IE ayant également problème de mise en cache qui est plus grave que la détection de la méthode de requête.
Vous devez malgré tout ajouter des busters de cache pour éviter la mise en cache, alors pourquoi ne pas utiliser un autre indicateur pour spécifier l’appel ajax - ou mieux, vous pouvez utiliser une URL différente, comme http://ajax.mysite.com/endpoint/sevice?params
$headers = Apache_request_headers();
$is_ajax = (isset($headers['X-Requested-With']) && $headers['X-Requested-With'] == 'XMLHttpRequest');
La meilleure solution pour s'assurer qu'une demande HTTP est vraiment envoyée via AJAX utilise la vérification SESSION, vous envoyez session_id dans un paramètre get et vous vérifiez si cette session est autorisée ou non!
Je suis d'accord Pekka. Aucune méthode native fiable entre les faces avant et arrière ne permet de détecter automatiquement si un client appelle réellement un point de terminaison à l'aide d'AJAX.
Pour ma propre utilisation, je dispose de peu de moyens principaux pour vérifier si un client demande l'un de mes points de terminaison:
Je peux utiliser HTTP_X_REQUESTED_WITH lorsque je ne suis pas dans un contexte interdomaine.
au lieu de cocher "X-required-with", je vérifie $ _SERVER ['HTTP_Origin'] (qui est envoyé à partir de la demande AJAX) dans le but de gérer les autorisations entre domaines. La plupart du temps, la raison principale pour laquelle je vérifie si une demande est une demande AJAX, est surtout à cause des autorisations entre domaines, en utilisant ce code PHP: header ('Access-Control-Allow- Origine: '. $ _ SERVER [' HTTP_Origin ']); // Si ce "HTTP_Origin" est dans ma liste blanche
mes API attendent du client qu’il explicite, dans quelques cas, le type de données (JSON, HTML, etc.) dans un GET ou un POST var. Par exemple, je vérifie si $ _REQUEST ['ajax'] n'est pas vide ou égal à une valeur attendue.