J'essaye de faire un appel AJAX (via JQuery) qui lancera un processus assez long. J'aimerais que le script envoie simplement une réponse indiquant que le processus a commencé, mais JQuery ne retournera pas la réponse tant que le script PHP n'est pas exécuté.
J'ai essayé cela avec un en-tête "close" (ci-dessous), et aussi avec la mise en mémoire tampon de sortie; ni l'un ni l'autre ne semble fonctionner. Des suppositions? ou est-ce quelque chose que je dois faire dans JQuery?
<?php
echo( "We'll email you as soon as this is done." );
header( "Connection: Close" );
// do some stuff that will take a while
mail( '[email protected]', "okay I'm done", 'Yup, all done.' );
?>
Réponses:
La page de manuel PHP suivante (y compris les notes de l'utilisateur) suggère plusieurs instructions sur la façon de fermer la connexion TCP au navigateur sans terminer le script PHP:
Soi-disant, cela nécessite un peu plus que l'envoi d'un en-tête fermé.
OP confirme alors: oui, cela a fait l'affaire: pointant vers la note utilisateur # 71172 (novembre 2006) copiée ici:
Plus tard en juillet 2010, dans une réponse connexe, Arctic Fire a ensuite lié deux autres notes d'utilisateur qui faisaient suite à celle ci-dessus:
la source
Connection: close
tête peut être écrasé par les autres logiciels de la pile, par exemple, le proxy inverse dans le cas d'un CGI (j'ai observé ce comportement avec nginx). Voir la réponse de @hanshenrik à ce sujet. En général,Connection: close
est exécuté côté client et ne doit pas être considéré comme une réponse à cette question. La connexion doit être fermée du côté serveur .Il est nécessaire d'envoyer ces 2 en-têtes:
Puisque vous devez connaître la taille de votre sortie, vous devrez mettre votre sortie en mémoire tampon, puis la vider dans le navigateur:
De plus, si votre serveur Web utilise la compression automatique gzip sur la sortie (c'est-à-dire Apache avec mod_deflate), cela ne fonctionnera pas car la taille réelle de la sortie est modifiée et la Content-Length n'est plus précise. Désactivez la compression gzip du script particulier.
Pour plus de détails, visitez http://www.zulius.com/how-to/close-browser-connection-continue-execution
la source
header("Content-Encoding: none\r\n");
cette façon, Apache ne la compressera pas.ob_flush()
n'est pas nécessaire et provoque en fait un avisfailed to flush buffer
. Je l'ai retiré et cela a très bien fonctionné.ob_flush()
ligne était nécessaire.Vous pouvez utiliser Fast-CGI avec PHP-FPM pour utiliser le
fastcgi_end_request()
fonction . De cette manière, vous pouvez continuer à effectuer certains traitements pendant que la réponse a déjà été envoyée au client.Vous trouvez ceci dans le manuel PHP ici: FastCGI Process Manager (FPM) ; Mais cette fonction n'est pas spécifiquement documentée dans le manuel. Voici l'extrait du PHP-FPM: PHP FastCGI Process Manager Wiki :
fastcgi_finish_request ()
Portée: fonction php
Catégorie: Optimisation
Cette fonctionnalité vous permet d'accélérer la mise en œuvre de certaines requêtes php. L'accélération est possible lorsque des actions en cours d'exécution du script n'affectent pas la réponse du serveur. Par exemple, l'enregistrement de la session dans Memcached peut se produire une fois que la page a été formée et transmise à un serveur Web.
fastcgi_finish_request()
est une fonctionnalité php, qui arrête la sortie de la réponse. Le serveur Web commence immédiatement à transférer la réponse "lentement et tristement" vers le client, et php peut en même temps faire beaucoup de choses utiles dans le contexte d'une requête, comme enregistrer la session, convertir la vidéo téléchargée, gérer toutes sortes de choses des statistiques, etc.fastcgi_finish_request()
peut invoquer l'exécution de la fonction d'arrêt.Note:
fastcgi_finish_request()
a une bizarrerie où les appels àflush
,print
ouecho
prendra fin tôt le script.Pour éviter ce problème, vous pouvez appeler
ignore_user_abort(true)
juste avant ou après l'fastcgi_finish_request
appel:la source
Version complète:
la source
Une meilleure solution consiste à créer un processus d'arrière-plan. C'est assez simple sur unix / linux:
Vous devriez regarder cette question pour de meilleurs exemples:
PHP exécute un processus d'arrière-plan
la source
En supposant que vous disposez d'un serveur Linux et d'un accès root, essayez ceci. C'est la solution la plus simple que j'ai trouvée.
Créez un nouveau répertoire pour les fichiers suivants et accordez-lui toutes les autorisations. (Nous pouvons le rendre plus sûr plus tard.)
Mettez ceci dans un fichier appelé
bgping
.Notez le
&
. La commande ping s'exécutera en arrière-plan pendant que le processus en cours passera à la commande echo. Il enverra une requête ping à www.google.com 15 fois, ce qui prendra environ 15 secondes.Rendez-le exécutable.
Mettez ceci dans un fichier appelé
bgtest.php
.Lorsque vous demandez bgtest.php dans votre navigateur, vous devriez obtenir la réponse suivante rapidement, sans attendre environ 15 secondes pour que la commande ping se termine.
La commande ping doit maintenant être exécutée sur le serveur. Au lieu de la commande ping, vous pouvez exécuter un script PHP:
J'espère que cela t'aides!
la source
Voici une modification du code de Timbo qui fonctionne avec la compression gzip.
la source
Je suis sur un hôte partagé et je suis
fastcgi_finish_request
configuré pour quitter complètement les scripts. Je n'aime pas non plus laconnection: close
solution. Son utilisation force une connexion distincte pour les demandes suivantes, ce qui coûte des ressources serveur supplémentaires. J'ai luTransfer-Encoding: cunked
l'article de Wikipédia et j'ai appris que cela0\r\n\r\n
met fin à une réponse. Je n'ai pas testé cela de manière approfondie sur les versions de navigateurs et les appareils, mais cela fonctionne sur les 4 de mes navigateurs actuels.la source
Vous pouvez essayer de faire du multithreading.
vous pouvez créer un script qui effectue un appel système (en utilisant shell_exec ) qui appelle le binaire php avec le script pour faire votre travail comme paramètre. Mais je ne pense pas que ce soit le moyen le plus sûr. Peut-être que vous pouvez améliorer les choses en chrootant le processus php et d'autres choses
Alternativement, il existe une classe chez phpclasses qui fait cela http://www.phpclasses.org/browse/package/3953.html . Mais je ne connais pas les spécificités de l'implémentation
la source
&
caractère pour exécuter le processus en arrière-plan.TL; DR Réponse:
Réponse de fonction:
la source
Votre problème peut être résolu en faisant de la programmation parallèle en php. J'ai posé une question à ce sujet il y a quelques semaines ici: Comment utiliser le multi threading dans les applications PHP
Et j'ai obtenu d'excellentes réponses. J'en ai beaucoup aimé un en particulier. L'auteur a fait référence au tutoriel Easy Parallel Processing en PHP (septembre 2008; par johnlim) qui peut en fait très bien résoudre votre problème car je l'ai déjà utilisé pour traiter un problème similaire survenu il y a quelques jours.
la source
La réponse de Joeri Sebrechts est proche, mais elle détruit tout contenu existant qui pourrait être mis en mémoire tampon avant que vous ne souhaitiez vous déconnecter. Il n'appelle pas
ignore_user_abort
correctement, ce qui permet au script de se terminer prématurément. La réponse du diyisme est bonne mais n'est pas générique. Par exemple, une personne peut avoir plus ou moins de tampons de sortie que cette réponse ne gère pas, donc cela peut simplement ne pas fonctionner dans votre situation et vous ne saurez pas pourquoi.Cette fonction vous permet de vous déconnecter à tout moment (tant que les en-têtes n'ont pas encore été envoyés) et conserve le contenu que vous avez généré jusqu'à présent. Le temps de traitement supplémentaire est illimité par défaut.
Si vous avez également besoin de mémoire supplémentaire, allouez-la avant d'appeler cette fonction.
la source
Remarque pour les utilisateurs de mod_fcgid (veuillez l'utiliser à vos risques et périls).
Solution rapide
La réponse acceptée de Joeri Sebrechts est en effet fonctionnelle. Cependant, si vous utilisez mod_fcgid, vous constaterez peut-être que cette solution ne fonctionne pas d'elle-même. En d'autres termes, lorsque la fonction de vidage est appelée, la connexion au client ne se ferme pas.
Le
FcgidOutputBufferSize
paramètre de configuration de mod_fcgid peut être à blâmer. J'ai trouvé cette astuce dans:Après avoir lu ce qui précède, vous pouvez arriver à la conclusion qu'une solution rapide serait d'ajouter la ligne (voir «Exemple d'hôte virtuel» à la fin):
soit dans votre fichier de configuration Apache (par exemple, httpd.conf), votre fichier de configuration FCGI (par exemple, fcgid.conf) ou dans votre fichier d'hôtes virtuels (par exemple, httpd-vhosts.conf).
Détails et une deuxième solution
La solution ci-dessus désactive la mise en mémoire tampon effectuée par mod_fcgid soit pour l'ensemble du serveur, soit pour un hôte virtuel spécifique. Cela peut entraîner une baisse des performances de votre site Web. D'un autre côté, cela peut ne pas être le cas puisque PHP effectue lui-même la mise en mémoire tampon.
Si vous ne souhaitez pas désactiver la mise en mémoire tampon de mod_fcgid , il existe une autre solution ... vous pouvez forcer ce tampon à se vider .
Le code ci-dessous fait exactement cela en s'appuyant sur la solution proposée par Joeri Sebrechts:
Ce que la ligne de code ajoutée fait essentiellement est de remplir le tampon de mod_fcgi , le forçant ainsi à se vider. Le nombre "65537" a été choisi car la valeur par défaut de la
FcgidOutputBufferSize
variable est "65536", comme mentionné dans la page Web Apache pour la directive correspondante . Par conséquent, vous devrez peut-être ajuster cette valeur en conséquence si une autre valeur est définie dans votre environnement.Mon environnement
Exemple d'hôte virtuel
la source
cela a fonctionné pour moi
la source
Ok, donc fondamentalement la façon dont jQuery fait la requête XHR, même la méthode ob_flush ne fonctionnera pas car vous ne pouvez pas exécuter une fonction sur chaque onreadystatechange. jQuery vérifie l'état, puis choisit les actions appropriées à entreprendre (terminé, erreur, succès, délai d'expiration). Et bien que je n'ai pas pu trouver de référence, je me souviens avoir entendu dire que cela ne fonctionne pas avec toutes les implémentations XHR. Une méthode qui, je pense, devrait fonctionner pour vous est un croisement entre le sondage ob_flush et le sondage pour toujours.
Et comme les scripts sont exécutés en ligne, lorsque les tampons sont vidés, vous obtenez une exécution. Pour rendre cela utile, remplacez le fichier console.log par une méthode de rappel définie dans la configuration de votre script principal pour recevoir les données et agir en conséquence. J'espère que cela t'aides. Salut, Morgan.
la source
Une autre solution consiste à ajouter le travail à une file d'attente et à créer un script cron qui vérifie les nouveaux travaux et les exécute.
J'ai dû le faire de cette façon récemment pour contourner les limites imposées par un hôte partagé - exec () et al était désactivé pour PHP exécuté par le serveur Web mais pouvait fonctionner dans un script shell.
la source
Si la
flush()
fonction ne fonctionne pas. Vous devez définir les options suivantes dans php.ini comme:la source
Dernière solution de travail
la source
Après avoir essayé de nombreuses solutions différentes de ce fil (après qu'aucune d'elles n'a fonctionné pour moi), j'ai trouvé une solution sur la page officielle PHP.net:
la source