PHP: Comment POST devient $_POST

CéroceCéroce Membre, Modérateur
Bonjour à  tous,

Voici ce que je souhaite faire:
- envoyer une requête HTTP POST avec une appli (via NSMutableRequest)
- avec PHP, récupérer les paramètres dans la variable $_POST.

Le problème est que j'ignore comment formatter le corps de ma requête HTTP.
Par exemple, dans mon script PHP, si je veux accéder à  $_POST['auteur'] que doit contenir le corps de la requête ? En d'autres termes, comment PHP convertit-il le corps de la requête POST en un dictionnaire ?

Réponses

  • AliGatorAliGator Membre, Modérateur
    10:17 modifié #2
    En fait cela dépend du Content-Type que tu utilises.
    Dire "j'envoie mes données en POST" ne suffit pas en pratique : quand tu utilises la méthode POST, tu mets ensuite plein de données dans le corps de la requête HTTP, et la façon dont ce corps de message est organisé/formatté dépend du Content-Type que tu as choisi.

    Les deux cas les plus courant restent cependant les Content-Type utilisés par les formulaires HTML <form> :
    1) soit le content-type "application/x-www-urlencoded" et qui en fait n'est rien d'autre que le même format que celui utilisé par le GET sauf qu'au lieu de mettre tes données dans l'URL derrière le "?" tu les mets dans le corps de la requête. Par exemple le "body" de ta NSMutableRequest pourra donc être qqch comme "nom=Renaud&site=www.ceroce.com&messages=1135", donc la même chose que si tu passais en GET après "?", sauf que c'est dans le corps de la requête et pas dans l'URL. Et dans ce cas côté PHP tu retrouveras $_POST['nom'] et $_POST['site'] et $_POST['messages'].



    2) soit le content-type "multipart/form-data" qui découpe le corps de message en plusieurs parties (d'où le "multipart" en utilisant une chaà®ne arbitraire (que l'on appelle le "boundary" pour indiquer le passage d'une partie à  l'autre (en général on utilise un truc comme "
    BlaBlaTexteUnique", un truc qui ne risque pas de se retrouver dans le contenu de tes données). Chaque partie possède ensuite alors son propre Content-Type, qui bien souvent est du simple texte, mais peut aussi être des données binaires.

    On utilise plus souvent ce content-type quand on a justement besoin d'envoyer des données binaires (fichier, image, ...) dans la requête POST, puisque le cas 1 avec le type "x-www-urlencoded" ne permet pas d'envoyer du binaire (tout comme le GET). Du coup ce format est un tout petit peu plus compliqué à  générer et malheureusement Cocoa ne fournit pas d'outils tout fait dans NSMutableRequest pour te faciliter la génération de ce corps de requête.

    Tu peux tout de même le faire toi-même car en réalité c'est pas bien méchant de construire ce genre de corps de requête (il suffit de faire une boucle for sur chaque clé, pour chaque clé tu écris une ligne avec le Content-Disposition et le Content-Type, puis un saut de ligne puis la valeur de ta clé), ou sinon tu as ASIHTTPRequest, qui est une classe qui traà®ne sur internet qui te permet de faire cela aussi (bon je suis pas fan car elle a des leaks cette classe, mais bon)
  • muqaddarmuqaddar Administrateur
    février 2011 modifié #3
    Hello,

    Moi je fais comme ça (avec ASIHTTPREQUEST, mais c'est presque pareil sans le framework) :

    [request setPostValue:@&quot;Country&quot; forKey:@&quot;wine[country]&quot;];<br />[request setPostValue:@&quot;Region&quot; forKey:@&quot;wine[region]&quot;];
    


    Par contre jé récupère en ruby (désolé) :

    @item = Wine.new params[:wine]
    


    le hash params[:wine] est créé tout seul à  partir des valeurs POST...

    Mais bon en PHP, doit y avoir un truc similaire ?!

    En fait ta question est bizarre.  :-*
    Si tu fais ça :

    [request setPostValue:@&quot;toto&quot; forKey:@&quot;auteur&quot;];<br />[request setPostValue:@&quot;titi&quot; forKey:@&quot;prenom&quot;];
    


    ça doit te suffire puisque ça envoie les valeurs les unes à  la suite des autres.

    $_POST['auteur']
    $_POST['prenom']

  • muqaddarmuqaddar Administrateur
    10:17 modifié #4
    Je me dépêche d'écrire et encore il me grille cet Ali...  >:D
  • AliGatorAliGator Membre, Modérateur
    février 2011 modifié #5
    Au fait pour référence, tout est détaillé/expliqué dans la norme HTTP
    c'est ici et c'est sans doute bien plus clair avec des exemples qu'ils fournissent etc

    En résumé si tu n'as que des données texte à  transporter, c'est très simple, tu fais comme pour du GET mais tu mets dans le PostBody.
    Si tu as des données binaires, voilà  pour te donner une idée à  quoi va ressembler ta requête
    NSMutableURLRequest* req = ...<br />...<br />NSString* boundary = @&quot;BouNDarY&quot;; // chaà®ne arbitraire de séparation<br />[req setContentType:[NSString stringWithFormat:@&quot;multipart/form-data; boundary=%@&quot;,boundary];<br /><br />NSMutableArray* parts = [[NSMutableArray alloc] init];<br /><br />// construction de chaque &quot;part&quot; en indiquant le content-type et content-disposition de chacun<br />for(NSString* key in dataDic) {<br />&nbsp; NSString* part = [NSString stringWithFormat:<br />&nbsp;  @&quot;content-disposition: form-data; name=&#092;&quot;%@&#092;&quot;&#092;r&#092;n&quot; /* key name */<br />&nbsp; &nbsp; &quot;content-type: text/plain; charset=utf-8&#092;r&#092;n&quot;<br />&nbsp; &nbsp; &quot;&#092;r&#092;n&quot;<br />&nbsp; &nbsp; &quot;%@&#092;r&#092;n&quot;, /* key value */<br />&nbsp; &nbsp; boundary,key,[dataDic valueForKey:key] ];<br />&nbsp; [parts addObject:part];<br />}<br /><br />// assemblage des &quot;parts&quot;<br />NSString* body = [NSString stringWithFormat:<br />&nbsp;  @&quot;--%@&#092;r&#092;n&quot; /* boundary de début */<br />&nbsp; &nbsp; &quot;%@&quot; /* concaténation des parts, séparées par le boundary */<br />&nbsp; &nbsp; &quot;--%@--&quot;, /* boundary de fin (le dernier est avec deux &quot;--&quot; derrière, cf la norme) */<br />&nbsp; &nbsp; boundary ,<br />&nbsp; &nbsp; [parts componentsJoinedByString:[NSString stringWithFormat:@&quot;--%@&#092;r&#092;n&quot;,boundary],<br />&nbsp; &nbsp; boundary];<br />[parts release];<br />[req setHTTPBody:body];
    
    Bon c'est fait en live tapé directement dans PommeDev, pas testé, mais c'est l'idée
  • CéroceCéroce Membre, Modérateur
    10:17 modifié #6
    Merci à  vous deux. En particulier à  Ali qui a pleinement répondu à  ma question, je comprends enfin à  quoi correspond le champ content-type.

    En fait, vous parliez d'ASIHTTPRequest dans un autre post, alors je suis allé voir, sans comprendre à  quoi elle servait. Je m'en servirai peut-être (quoique s'il y a des fuites mémoire...), mais à  terme je voudrais construire mon propre web service, et je veux savoir comment ça fonctionne sous le capôt.

    @muqaddar: Je ne crois pas que ma question soit si bizarre  ???. Comme tu le supposais très justement, $_POST[] est un dictionnaire fourni par PHP, qui contient, par exemple pour un formulaire, les différentes saisies. J'avais besoin de savoir comment PHP (ou Apache ?) créait ce dictionnaire.

    Merci encore.
  • AliGatorAliGator Membre, Modérateur
    10:17 modifié #7
    dans 1297791092:

    Hello,

    Moi je fais comme ça (avec ASIHTTPREQUEST, mais c'est presque pareil sans le framework) :
    Heu c'est difficilement pareil sans le framework ASIHTTPRequest puisque "setPostValue:forKey:" est une méthode de ASIHTTPRequest non disponible dans NSMutableURLRequest !

    Mais bon le principe utilisé par ASIHTTPRequest reste sous le capot celui que j'ai énoncé, à  savoir juste au moment d'envoyer la requête ils construisent leur "body" pour qu'il suive la norme et le content-type multipart/form-data :
    Content-Type: multipart/form-data; boundary=AaB03x
    
    &nbsp;  --AaB03x<br />&nbsp;  Content-Disposition: form-data; name=&quot;submit-name&quot;<br /><br />&nbsp;  Larry<br />&nbsp;  --AaB03x<br />&nbsp;  Content-Disposition: form-data; name=&quot;files&quot;; filename=&quot;file1.txt&quot;<br />&nbsp;  Content-Type: text/plain<br /><br />&nbsp;  ... contents of file1.txt ...<br />&nbsp;  --AaB03x--
    
  • muqaddarmuqaddar Administrateur
    10:17 modifié #8
    dans 1297792168:

    @muqaddar: Je ne crois pas que ma question soit si bizarre  ???. Comme tu le supposais très justement, $_POST[] est un dictionnaire fourni par PHP, qui contient, par exemple pour un formulaire, les différentes saisies. J'avais besoin de savoir comment PHP (ou Apache ?) créait ce dictionnaire.


    Je m'étais positionné une étape plus loin... comment récupérer un array de dictionnaires dans la requête POST qui est elle même un dicitonnaire. C'est la faute à  Ruby et Rails.

    Moi je te conseille ASIHTTPREQUEST, il est très pratique (c'est déjà  fait et récupéré 600 requêtes à  la suite et la mémoire n'a pas sauté...). ;)
  • muqaddarmuqaddar Administrateur
    10:17 modifié #9
    Heu c'est difficilement pareil sans le framework ASIHTTPRequest puisque "setPostValue:forKey:" est une méthode de ASIHTTPRequest non disponible dans NSMutableURLRequest !


    Oui, elle mâche le travail, ou plutôt elle l'éclaircit. Je parlais du principe... ;)

    Bon, sinon, c'est quoi tous ces gens qui font du PHP ?  >:)
  • AliGatorAliGator Membre, Modérateur
    10:17 modifié #10
    dans 1297792168:

    @muqaddar: Je ne crois pas que ma question soit si bizarre  ???
    En fait c'est parce qu'Alex utilise la classe-qui-fuit-mais-qui-permet-de-te-faciliter-les-choses qu'il dit ça :P
    Du coup avec cette classe ASIHTTPRequest en effet tu n'as pas à  te soucier de comment c'est fait sous le capot.

    Mais si je passe un Build & Analyze ou mes scripts perl de vérification de mémoire (j'ai en particulier un script qui vérifie que les variables d'instance sont bien relâchées dans le dealloc, chose que Build & Analyze ne fait pas), j'ai des leaks qui me sont remontés. En pratique de même si je fais des requêtes assez simples avec ASIHTTPRequest ça passe, mais si j'envoie des grosses images et plein de données, j'ai quelques fuites à  force. C'est pas le gros leak énorme, mais cumulé (surtout de nos jours où avec le multi-tâche sous iOS l'appli n'est quasiment jamais quittée) ça peut monter et finir par envoyer des memory warnings.

    Bon après je dis ça de ce que j'ai détecté d'avec mes scripts ou avec Instruments, mais je n'ai pas fouillé plus loin (ça fait partie des tâches auxquelles je dois m'atteler pour optimiser mon application, que de corriger cette classe ASIHTTPRequest si je trouve d'où ça vient... ou la réimplémenter à  ma façon sinon, ce qui me permettra... d'utiliser les blocks par exemple pour les callbacks de retour gniark gniark)
  • CéroceCéroce Membre, Modérateur
    10:17 modifié #11
    J'ai du code qui marche. Voilà  ce que ça donne pour la partie Cocoa:

    - (IBAction) submit:(id)sender<br />{<br />	// Attention, les caractères spéciaux (espaces, accents...) ne sont pas convertis.<br />	<br />	// Build the message content (url-encoded style)<br />	NSString *subject = [subjectTextField stringValue];<br />	NSString *comments = [commentsTextField stringValue];<br />	NSString *email = [emailTextField stringValue];<br />	<br />	NSString *message = [NSString stringWithFormat:@&quot;subject=%@&amp;comments=%@&amp;email=%@&quot;, subject, comments, email];<br />	NSData *messageData = [message dataUsingEncoding:NSUTF8StringEncoding];<br />	<br />	// Build the POST HTTP request<br />	NSURL *url = [NSURL URLWithString:@&quot;http://www.monsite.com/monscript.php&quot;];<br />	NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];	<br />	[request setHTTPMethod:@&quot;POST&quot;];<br />	[request setValue:@&quot;application/x-www-form-urlencoded&quot; forHTTPHeaderField:@&quot;Content-Type&quot;];<br />	[request setHTTPBody:messageData];<br />	<br />	// Create a data block to store the result<br />	if(httpData)<br />		[httpData release];	<br />	httpData = [[NSMutableData data] retain];<br />	<br />	// Sent the request<br />	NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];<br /><br />	[connection start];<br />}<br /><br />-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response<br />{<br /><br />}<br /><br />-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data<br />{<br />	[httpData appendData:data];<br />}<br /><br />-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error<br />{<br />	NSLog(@&quot;Erreur&quot;);<br />	<br />	[connection release];<br />	[httpData release];<br />	httpData = nil;<br />}<br /><br />-(void)connectionDidFinishLoading:(NSURLConnection *)connection<br />{<br />	NSString *message = [[NSString alloc] initWithData:httpData encoding:NSUTF8StringEncoding];<br />	[message autorelease];<br />	NSLog(@&quot;message: %@&quot;, message);<br /><br />	[connection release];<br />	[httpData release];<br />	httpData = nil;<br />}
    



    Et pour la partie PHP:

    &lt;?php<br /><br />$subject = $_POST&#91;&#39;subject&#39;];<br />$comments = $_POST&#91;&#39;comments&#39;];<br />$email = $_POST&#91;&#39;email&#39;];<br /><br />echo &quot;subject=&quot;.$subject.&quot;&#092;n&quot;;<br />echo &quot;comments=&quot;.$comments.&quot;&#092;n&quot;;<br />echo &quot;email=&quot;.$email.&quot;&#092;n&quot;;<br /><br />?&gt;
    
  • AliGatorAliGator Membre, Modérateur
    10:17 modifié #12
    [EDIT Modo]Le sujet ayant dérivé sur Ruby on Rails, les messages relatifs à  RoR ont été séparés dans un sujet dédié que vous pouvez retrouver ici
Connectez-vous ou Inscrivez-vous pour répondre.