La technique Ajax permet de modifier partiellement une page affichée par le navigateur pour la mettre à jour sans avoir à recharger cette dernière dans son intégralité. Elle dépend de XMLHttpRequest, objet intégré coté client utilisable en Javascript.
Il existe une multitude de tutoriels décrivant le fonctionnement et techniques.
Pour ce post, je m'intéresserai principalement à une limitation de la majorité des navigateurs actuels, due à des raisons de sécurité, concernant l'utilisation de domains différents.
En effet, une script JS lancé sur une page www.name.com ne peut normalement pas diriger d'objet vers un domain différent.
Là où cela devient vraiment embêtant, c'est que les subdomains sont égalements limités : impossible d'utiliser, par exemple, l'adresse ww1.name.com pour ces mêmes fonctions.
Dans le cas où vous devriez lancer des scripts sur différents serveurs, comme pour l'envoi d'images à un serveur Master, depuis un serveur Slave (Post à venir), le navigateur bloquerait ces communications.
Alors comment faire ?
La solution s'appelle le "Cross-site Ajax".
L'idée est de créer un fichier PHP fonctionnant comme un proxy et dont nous allons nous servir en appel Ajax pour communiquer avec les différents domains/subdomains.
Je vous propose donc un fichier permettant d'outrepasser les protections navigateurs, basé sur l'extension cURL (librairie libcurl, voir post Plus rapide que file_get_contents : optez pour cURL !) :
Contenu du fichier : csaproxy.php
<?php
header('Content-type: text/html; charset=iso-8859-1');
if ( $_GET['pass'] != "abcde12345" ) die(); //protection par mot de passe lors de l'appel
function curl_http_request(
$url = 'www.domain.com/index.php', /* Target URL */
$getdata = array(), /* HTTP GET Data ie. array('var1' => 'val1', 'var2' => 'val2') */
$postdata = array(), /* HTTP POST Data ie. array('var1' => 'val1', 'var2' => 'val2') */
$filesdata = array(), /* HTTP FILES Data ie. array('var1' => 'val1', 'var2' => 'val2') */
$cookie = array() /* HTTP Cookie Data ie. array('var1' => 'val1', 'var2' => 'val2') */
) {
$curlopt = array();
$cookie_str = '';
$getdata_str = count($getdata) ? '?' : '';
foreach ($getdata as $k => $v) $getdata_str .= (strlen($getdata_str)>0?'&':'').urlencode($k).'='.urlencode($v);
//assignation uploads en POST : _POST['champ']=filetmpname et _POST['champ_real']=filename
foreach ($filesdata as $k => $v) {
if ( $filesdata[$k]['error'] == UPLOAD_ERR_OK ) {
$postdata[$k]='@'.$filesdata[$k]['tmp_name'];
$postdata[$k."_real"]=$filesdata[$k]['name'];
}
}
foreach ($cookie as $k => $v) $cookie_str .= (strlen($cookie_str)>0?'; ':'').urlencode($k).'='.urlencode($v);
if ( count($postdata) ) {
$curlopt = array (
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $postdata
);
}
$default_curlopt = array(
CURLOPT_TIMEOUT => 2, //timeout 2sec
CURLOPT_FAILONERROR => 1, //si page error, on ne d/l pas
CURLOPT_RETURNTRANSFER => 1, //return le transfert as a string
CURLOPT_FOLLOWLOCATION => 1, //on follow si redirection header desactive par défaut
CURLOPT_USERAGENT => $_SERVER['HTTP_USER_AGENT']?$_SERVER['HTTP_USER_AGENT']:"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 AlexaToolbar/alxf-1.54 Firefox/3.6.13 GTB7.1"
);
$curlopt = array(CURLOPT_URL => $url.$getdata_str) + $curlopt + $default_curlopt;
// Création d'une nouvelle ressource cURL
$ch = curl_init();
// Configuration de l'URL et d'autres options
curl_setopt_array($ch, $curlopt);
//Envoi des données
$results_returned = curl_exec($ch);
if ( $results_returned === false ) trigger_error(curl_error($ch));
// Fermeture de la session cURL
curl_close($ch);
return $results_returned;
}
//destinations autorisées, en double pour redoubler de vigilance
$accepted_file_proxycsa=array(
'/script.php',
'/script.php' => 'www.domain.com',
'/main/postit.php',
'/main/postit.php' => 'sub.domain.com'
);
if ( in_array($_GET['filename_csa'],$accepted_file_proxycsa) ) {
$target_filename=$_GET['filename_csa'];
$target_site=$accepted_file_proxycsa[$_GET['filename_csa']];
}
if (( strlen($target_filename) > 0 ) && ( strlen($target_site) > 0 )) {
echo curl_http_request($target_site.$target_filename,$_GET,$_POST,$_FILES,$_COOKIE);
}
?>
Une fois ce fichier uploadé sur votre serveur, vous pouvez désormais appeler tout fichier présent dans n'importe quel domain/subdomain.
Ne pas oublier d'inclure les destinations autorisées dans le array $accepted_file_proxycsa. Vous pouvez également vous affranchir de ce passage et rediriger directement l'url contenu dans le $_GET.
Exemple de code Javascript incluant le cross-site Ajax :
<script type="text/javascript">
function csajax(CHOIX,idcible) {
var xhr_object = new Array;
xhr_object[CHOIX] = null;
if(window.XMLHttpRequest) // Firefox
xhr_object[CHOIX] = new XMLHttpRequest();
else if(window.ActiveXObject) // Internet Explorer
xhr_object[CHOIX] = new ActiveXObject("Microsoft.XMLHTTP");
else { // XMLHttpRequest non supporté par le navigateur
alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest...");
return;
}
xhr_object[CHOIX].open("POST", "http://<?php echo $_SERVER['SERVER_NAME']; ?>/csaprx.php?filename_csa=/main/postit.php", true);
xhr_object[CHOIX].onreadystatechange = function() {
if ( CHOIX == "postit" ) {
if (( xhr_object[CHOIX].readyState == 4) && ( xhr_object[CHOIX].responseText.length > 0 )) {
document.getElementById(idcible).innerHTML=xhr_object[CHOIX].responseText;
xhr_object[CHOIX].abort;
}
}
};
xhr_object[CHOIX].setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=iso-8859-1");
if ( CHOIX == "postit" ) {
var data = "message="+encodeURIComponent(document.getElementById('champ_msg').value)+'&auteur='+encodeURIComponent(document.getElementById('champ_auteur').value);
xhr_object[CHOIX].send(data);
}
}
</script>
function csajax(CHOIX,idcible) {
var xhr_object = new Array;
xhr_object[CHOIX] = null;
if(window.XMLHttpRequest) // Firefox
xhr_object[CHOIX] = new XMLHttpRequest();
else if(window.ActiveXObject) // Internet Explorer
xhr_object[CHOIX] = new ActiveXObject("Microsoft.XMLHTTP");
else { // XMLHttpRequest non supporté par le navigateur
alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest...");
return;
}
xhr_object[CHOIX].open("POST", "http://<?php echo $_SERVER['SERVER_NAME']; ?>/csaprx.php?filename_csa=/main/postit.php", true);
xhr_object[CHOIX].onreadystatechange = function() {
if ( CHOIX == "postit" ) {
if (( xhr_object[CHOIX].readyState == 4) && ( xhr_object[CHOIX].responseText.length > 0 )) {
document.getElementById(idcible).innerHTML=xhr_object[CHOIX].responseText;
xhr_object[CHOIX].abort;
}
}
};
xhr_object[CHOIX].setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=iso-8859-1");
if ( CHOIX == "postit" ) {
var data = "message="+encodeURIComponent(document.getElementById('champ_msg').value)+'&auteur='+encodeURIComponent(document.getElementById('champ_auteur').value);
xhr_object[CHOIX].send(data);
}
}
</script>
Formulaire HTML correspondant:
<input type="text" name="champ_msg">
<input type="button" value="Envoyer" onclick="csajax('postit','reponse');">
<div id="reponse"></div>
<input type="button" value="Envoyer" onclick="csajax('postit','reponse');">
<div id="reponse"></div>
Cet exemple enverra le contenu du champ_msg à http://sub.domain.com/main/postit.php et retournera le résultat dans le div reponse.
C'est aussi simple que ça !

