<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>psr-7 Archivi - Cesare Bordi | Innovation Manager &amp; Back-end Developer</title>
	<atom:link href="https://www.cesarebordi.it/tag/psr-7/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.cesarebordi.it/tag/psr-7/</link>
	<description>Innovare con soluzioni software efficaci e gioco di squadra</description>
	<lastBuildDate>Tue, 24 Nov 2020 07:48:42 +0000</lastBuildDate>
	<language>it-IT</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.4.3</generator>

<image>
	<url>https://www.cesarebordi.it/wp-content/uploads/2016/02/CB-logo-88x88.png</url>
	<title>psr-7 Archivi - Cesare Bordi | Innovation Manager &amp; Back-end Developer</title>
	<link>https://www.cesarebordi.it/tag/psr-7/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>PSR-7 Http Message: standard php per Request e Response.</title>
		<link>https://www.cesarebordi.it/psr-7-http-message-standard-php-request-response/</link>
					<comments>https://www.cesarebordi.it/psr-7-http-message-standard-php-request-response/#respond</comments>
		
		<dc:creator><![CDATA[cesarebordi]]></dc:creator>
		<pubDate>Wed, 23 Sep 2020 07:27:42 +0000</pubDate>
				<category><![CDATA[Lezioni]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[best practice]]></category>
		<category><![CDATA[developer]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php-fig]]></category>
		<category><![CDATA[phpfig]]></category>
		<category><![CDATA[psr]]></category>
		<category><![CDATA[psr-7]]></category>
		<category><![CDATA[psr7]]></category>
		<category><![CDATA[standard]]></category>
		<category><![CDATA[web developer]]></category>
		<category><![CDATA[webservice]]></category>
		<guid isPermaLink="false">https://www.cesarebordi.it/?p=1273</guid>

					<description><![CDATA[<p>PSR-7 Http Message del PHP-FIG propone interfacce php standard per rappresentare i messaggi Http di Request e Response.</p>
<p>L'articolo <a href="https://www.cesarebordi.it/psr-7-http-message-standard-php-request-response/">PSR-7 Http Message: standard php per Request e Response.</a> sembra essere il primo su <a href="https://www.cesarebordi.it">Cesare Bordi | Innovation Manager &amp; Back-end Developer</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><strong>PSR-7 Http Message</strong> del PHP-FIG propone interfacce <strong>php</strong> standard per rappresentare i <strong>messaggi Http</strong> di <strong>Request</strong> e <strong>Response</strong> oltre ad analizzarne il contenuto.</p>



<blockquote class="wp-block-quote"><p>HTTP messages are the foundation of web development.</p></blockquote>



<p>Standardizzare questo aspetto è importantissimo poiché i messaggi Http sono le fondamenta dello sviluppo web. I browser ed i client come cURL inviano <strong>richieste Http</strong> al server che fornisce un&#8217;adeguata <strong>risposta Http</strong>.</p>



<p>Di seguito analizzeremo le interfacce proposte dal <a href="https://www.php-fig.org/psr/psr-7/" target="_blank" rel="noreferrer noopener">PSR-7</a> che rappresentano astrazioni dei messaggi Http e degli elementi che li compongono. Per il significato delle parole chiave presenti nell&#8217;articolo si rimanda alle <a href="https://www.cesarebordi.it/psr-1-regole-scrittura-codice-php/#note" target="_blank" rel="noreferrer noopener">note dell’articolo sul PSR-1</a>.</p>



<h2 class="wp-block-heading">Http Request</h2>



<p>Iniziamo esaminando il contenuto di una <strong>Http Request</strong>.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; gutter: false; title: ; notranslate">
POST /path HTTP/1.1
Host: example.com

foo=bar&amp;baz=bat
</pre></div>


<p>La prima riga,  detta &#8220;request line&#8221;, contiene il <strong>metodo della richiesta Http</strong>, il <strong>target della richiesta Http</strong>, solitamente una URI assoluta o un percorso sul server web, la <strong>versione del protocollo Http</strong> utilizzato. A questo seguono una o più <strong>intestazioni Http</strong>, una riga vuota ed il <strong>corpo del messaggio</strong>.</p>



<h2 class="wp-block-heading">Http Response</h2>



<p>Esaminiamo ora il contenuto di una <strong>Http Response</strong>.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; gutter: false; title: ; notranslate">
HTTP/1.1 200 OK
Content-Type: text/plain

This is the response body
</pre></div>


<p>La prima riga di una <strong>Http Response</strong>, detta &#8220;status line&#8221;, contiene la <strong>versione del protocollo Http</strong>, il <strong>codice di stato Http</strong> ed una <strong>descrizione comprensibile</strong> del codice di stato. Come per il messaggio di richiesta, questa riga è seguita da una o più <strong>intestazioni Http</strong>, una riga vuota ed il <strong>corpo del messaggio</strong>.</p>



<h2 class="wp-block-heading">PSR-7: specifiche</h2>



<h3 class="wp-block-heading">Messaggi Http</h3>



<p>Un <strong>messaggio Http</strong> è una richiesta da un client ad un server o una risposta da un server ad un client. PSR-7 definisce le rispettive interfacce per i messaggi Http: <strong><em><code>Psr\Http\Message\RequestInterface</code></em></strong> e <strong><em><code>Psr\Http\Message\ResponseInterface</code></em></strong>.</p>



<p>Entrambe estendono <strong><em><code>Psr\Http\Message\MessageInterface</code></em></strong>.<br />Mentre <strong><em><code>&lt;a href=&quot;#MessageInterface&quot;&gt;Psr\Http\Message\MessageInterface&lt;/a&gt;</code></em></strong> <strong>PUÒ essere implementato</strong> direttamente, gli implementatori <strong>DOVREBBERO implementare</strong> <strong><em><code>Psr\Http\Message\RequestInterface</code></em></strong> e <strong><em><code>Psr\Http\Message\ResponseInterface</code></em></strong>.<br />Per migliorare la lettura dell&#8217;articolo, da qui in avanti verrà omesso il namespace <em><code>Psr\Http\Message</code></em> per riferirsi a queste interfacce.</p>



<h3 class="wp-block-heading">HTTP Headers</h3>



<h4 class="wp-block-heading">Nomi case-insensitive nei campi di intestazione.</h4>



<p>I <strong>messaggi Http</strong> possono includere vari campi nell&#8217;intestazione (header) <strong>senza distinzione tra maiuscole e minuscole</strong>. Allo stesso modo dovranno essere recuperate dalle classi che implementano <code>&lt;strong&gt;&lt;em&gt;&lt;a href=&quot;#MessageInterface&quot;&gt;MessageInterface&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;</code>. <br />Ad esempio, il recupero dell&#8217;intestazione <code>foo</code> restituirà lo stesso risultato del recupero dell&#8217;intestazione <code>FoO</code>. Allo stesso modo, l&#8217;impostazione dell&#8217;intestazione <code>Foo</code> sovrascriverà qualsiasi valore di intestazione <code>foo</code> precedentemente impostato.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
$message = $message-&gt;withHeader('foo', 'bar');

echo $message-&gt;getHeaderLine('foo');
// Outputs: bar

echo $message-&gt;getHeaderLine('FOO');
// Outputs: bar

$message = $message-&gt;withHeader('fOO', 'baz');

echo $message-&gt;getHeaderLine('foo');
// Outputs: baz
</pre></div>


<p>Nonostante le intestazioni possano essere recuperate senza distinzione tra maiuscole e minuscole, <strong>il case originale DEVE essere rispettato</strong> nell&#8217;implementazione, in particolar modo quando viene recuperato con <code>getHeaders()</code>. Questo perché applicazioni Http non conformi possono dipendere da un determinato caso.</p>



<h4 class="wp-block-heading">Campi di intestazione con valori multipli</h4>



<p>Per gestire campi di intestazione con più valori e fornire una migliore flessibilità nella gestione, le intestazioni possono essere recuperate da un&#8217;istanza di <code>&lt;strong&gt;&lt;em&gt;MessageInterface&lt;/em&gt;&lt;/strong&gt;</code> come array o stringa. Nel primo caso useremo <code>&lt;strong&gt;getHeader()&lt;/strong&gt;</code>, nel secondo <code>&lt;strong&gt;getHeaderLine()&lt;/strong&gt;</code>. </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
$message = $message
    -&gt;withHeader('foo', 'bar')
    -&gt;withAddedHeader('foo', 'baz');

$header = $message-&gt;getHeaderLine('foo');
// $header contiene: 'bar,baz'

$header = $message-&gt;getHeader('foo');
// &#x5B;'bar', 'baz']
</pre></div>


<p>Da notare che non tutti i valori di intestazione possono essere concatenati con la virgola (es: Set-Cookie). In questo caso gli utilizzatori <strong>DOVREBBERO usare metodo <code>getHeader()</code></strong> per recuperare tali intestazioni multivalore.</p>



<h4 class="wp-block-heading">Intestazione &#8220;Host&#8221;</h4>



<p>Nelle richieste, l&#8217;intestazione <code>Host</code> riporta l&#8217;host dell&#8217;URI, nonché l&#8217;host utilizzato per stabilire la connessione Tcp. Le specifiche del protocollo Http consentono però all&#8217;intestazione <code>Host</code> di differire da entrambi. Le implementazioni, se non viene fornita alcuna intestazione <code>Host</code>, <strong>DEVONO tentare di impostarla da un URI predefinito</strong> .</p>



<p><code>&lt;strong&gt;RequestInterface :: withUri (UriInterface $uri, $preserveHost = false)&lt;/strong&gt;</code>, per impostazione predefinita, sostituirà l&#8217;intestazione Host della richiesta restituita con quella dell&#8217;oggetto di tipo <code>&lt;strong&gt;UriInterface&lt;/strong&gt;</code> passatogli. Per mantenere il valore originale basterà passare <code>true</code> al secondo argomento (<code>$preservHost</code>). Ciò manterrà invariata l&#8217;intestazione Host a patto che il messaggio ne contenga una.</p>



<p>Questa tabella mostra cosa restituirà <code>getHeaderLin(&#039;Host&#039;)</code> per una richiesta restituita da <code>withUri()</code> con l&#8217;argomento <code>$preservHost</code> impostato su <code>true</code> in varie richieste iniziali e URI.</p>



<table>
  <thead>
    <tr>
      <th>Request Host header<sup>1</sup></th>
      <th>Request host component<sup>2</sup></th>
      <th>URI host component<sup>3</sup></th>
      <th>Result</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>’’</td>
      <td>’’</td>
      <td>’’</td>
      <td>’’</td>
    </tr>
    <tr>
      <td>’’</td>
      <td>foo.com</td>
      <td>’’</td>
      <td>foo.com</td>
    </tr>
    <tr>
      <td>’’</td>
      <td>foo.com</td>
      <td>bar.com</td>
      <td>foo.com</td>
    </tr>
    <tr>
      <td>foo.com</td>
      <td>’’</td>
      <td>bar.com</td>
      <td>foo.com</td>
    </tr>
    <tr>
      <td>foo.com</td>
      <td>bar.com</td>
      <td>baz.com</td>
      <td>foo.com</td>
    </tr>
  </tbody>
</table>



<ol><li>Valore dell&#8217;intestazione host prima dell&#8217;operazione.</li><li>Componente host dell&#8217;URI composto nella richiesta prima dell&#8217;operazione.</li><li>Componente host dell&#8217;URI settato tramite <code>withUri()</code>.</li></ol>



<h3 class="wp-block-heading">Streams</h3>



<p>I messaggi Http sono costituiti da una riga iniziale, alcune intestazioni ed un corpo che può essere anche molto grande. Rappresentare il body di un messaggio come una stringa potrebbe consumare molta memoria fino a precludere la possibiltà di lavorare con body di grandi dimensioni. <code>&lt;strong&gt;StreamInterface&lt;/strong&gt;</code> viene utilizzato proprio per nascondere i dettagli di implementazione quando un flusso di dati viene letto o scritto. Per le situazioni in cui una stringa sarebbe un&#8217;implementazione del messaggio appropriata, è possibile utilizzare flussi incorporati come <code>php://memory</code> e <code>php://temp</code>.<br /><br /><strong><code>StreamInterface</code></strong> espone diversi metodi che consentono di leggere, scrivere e scorrere gli stream in modo efficace.<br /><br />Gli stram espongono le loro capacità utilizzando tre metodi: <strong><code>isReadable()</code></strong>, <code>&lt;strong&gt;isWritable()&lt;/strong&gt;</code> e <code>&lt;strong&gt;isSeekable()&lt;/strong&gt;</code>. Gli oggetti che vogliono utilizzare uno stream possono utilizzare questi metodi per determinare se è in grado di soddisfare determinati requisiti.<br /><br />Ogni istanza di uno stream avrà diverse funzionalità: può essere di sola lettura, di sola scrittura o di lettura/scrittura. Può consentire un accesso casuale arbitrario (ricerca in avanti o indietro in qualsiasi posizione) o solo accesso sequenziale come nel caso di socket, pipe, o callback-based stream.<br /><br />Infine, <strong><code>StreamInterface</code></strong> definisce un metodo <strong><code>__toString()</code></strong> per recuperare o inviare l&#8217;intero contenuto del corpo in una sola volta.<br /><br />A differenza delle interfacce di Request e Response, <strong><code>StreamInterface</code></strong> interagisce con gli stream che, per loro natura, possono mutare durante il loro utilizzo. La raccomandazione di Php-Fig è di utilizzare flussi di sola lettura per le richieste lato server e le risposte lato client.</p>



<h3 class="wp-block-heading">Target della richiesta ed URI</h3>



<p>Secondo lo standard <a rel="noreferrer noopener" href="https://tools.ietf.org/html/rfc7230" target="_blank">RFC 7230</a> i messaggi di richiesta contengono uno dei seguenti tipi di &#8220;target&#8221;:</p>



<ul><li><strong>origin-form</strong>: costituito da <strong>percorso</strong> e, se presente, <strong>stringa della query</strong>. È solitamente definito come un URL relativo. I messaggi trasmessi via Tcp sono tipicamente di tipo <em>origin-form</em>; i dati di <em>scheme</em> e <em>authority</em> sono presenti tramite variabili CGI.</li><li><strong>absolute-form</strong>: costituito da <strong>scheme</strong>, <strong>authority</strong> (“[user-info@]host[:port]”, dove gli elementi tra parentesi sono facoltativi), <strong>percorso</strong> (se presente), <strong>stringa della query</strong> (se presente) e<strong> fragment</strong> ( se presente). È solitamente definito come un URI assoluto ed è l&#8217;unico che consente di specificare una URI come descritto nel <a rel="noreferrer noopener" href="https://tools.ietf.org/html/rfc3986" target="_blank">RFC 3986</a>. Questo modulo è comunemente usato quando si effettuano richieste ai proxy Http</li><li><strong>authority-form</strong>: costituito dalla sola <strong>authority.</strong> È solitamente utilizzato nelle CONNECT Request per stabilire una connessione tra un client Http e un server proxy.</li><li><strong>asterisk-form</strong>: costituito unicamente dalla <strong>stringa asterisco</strong> ( &#8221; * &#8221; ). È solitamente utilizzato con il <strong>metodo OPTIONS</strong> per determinare le capacità generali di un server web.</li></ul>



<p>Oltre a questi target di richiesta, c&#8217;è spesso un &#8220;URL effettivo&#8221; che è separato dal target di richiesta. L&#8217;URL effettivo non viene trasmesso all&#8217;interno di un messaggio Http, ma viene utilizzato per determinare il protocollo (http / https), la porta e l&#8217;host-name per effettuare la richiesta.</p>



<p>L&#8217;URL effettivo è rappresentato da <code>&lt;strong&gt;UriInterface&lt;/strong&gt;</code>. <code>UriInterface</code> rappresenta gli URI Http e Https fornendo i metodi per interagire con le varie parti dell&#8217;URI evitendo un&#8217;analisi ripetuta dell&#8217;URI. Specifica inoltre un metodo <code>__toString()</code> per rappresentare la URI come stringa.</p>



<p>Quando si recupera la destinazione della richiesta con <code>&lt;strong&gt;getRequestTarget()&lt;/strong&gt;</code>, per impostazione predefinita questo metodo utilizzerà l&#8217;oggetto URI ed estrarrà tutti i componenti necessari per costruire l&#8217;origin-form che è il request-target più comune.</p>



<p>Se si desidera utilizzare uno degli altri tre tipi di target o se l&#8217;utente desidera sovrascrivere esplicitamente il target della richiesta si utilizzerà il metodo <code>&lt;strong&gt;withRequestTarget()&lt;/strong&gt;</code>. La chiamata a questo metodo non influisce sull&#8217;URI, poiché viene restituito da <code>&lt;strong&gt;getUri()&lt;/strong&gt;</code>.</p>



<p>Ad esempio, un utente potrebbe voler effettuare una richiesta in formato asterisco a un server:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
$request = $request
    -&gt;withMethod('OPTIONS')
    -&gt;withRequestTarget('*')
    -&gt;withUri(new Uri('https://example.org/'));
</pre></div>


<p>L&#8217;esempio creerebbe questo tipo di richiesta Http:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
OPZIONI * HTTP / 1.1
</pre></div>


<p>Il client Http sarà poi in grado di utilizzare l&#8217;URL effettivo (<code>getUri()</code>) per determinare il protocollo, l&#8217;host-name e la porta Tcp.</p>



<p>Un client Http <strong>DEVE</strong> ignorare i valori di <code>&lt;strong&gt;Uri::getPath()&lt;/strong&gt;</code> e <code>&lt;strong&gt;Uri::getQuery()&lt;/strong&gt;</code> ed utilizzare il valore restituito da <code>&lt;strong&gt;getRequestTarget()&lt;/strong&gt;</code> che concatena questi due valori.</p>



<p>I client che scelgono di non implementare 1 o più dei 4 request-target form, <strong>DEVONO</strong> comunque utilizzare <code>&lt;strong&gt;getRequestTarget()&lt;/strong&gt;</code>. Questi client <strong>DEVONO</strong> rifiutare <strong>request-target</strong> che non supportano e <strong>NON DEVONO</strong> utilizzare i valori di <code>&lt;strong&gt;getUri()&lt;/strong&gt;</code>.</p>



<p><code>&lt;strong&gt;RequestInterface&lt;/strong&gt;</code> fornisce metodi per recuperare il target della richiesta o creare una nuova istanza specificando il target. Per impostazione predefinita, se non viene specificato il request-target, <code>&lt;strong&gt;getRequestTarget()&lt;/strong&gt;</code> restituirà l&#8217;origin-form della URI composta o &#8221; / &#8221; se non è stata composta una URI. <strong><code>withRequestTarget($requestTarget</code>)</strong> crea una nuova istanza con il request-target specificato ed è utile per creare connessioni verso un server.</p>



<h3 class="wp-block-heading">Richieste Server-side</h3>



<ul><li><code>&lt;strong&gt;RequestInterface&lt;/strong&gt;</code> permette di rappresentare un messaggio di richiesta Http, ma le richieste lato server side richiedono un&#8217;attenzione particolare. I processi server-side devono tener conto della Common Gateway Interface (CGI) e dell&#8217;interazione di PHP con essa attraverso le sue via Server API (SAPI) . PHP ci fornisce una semplificazione per la gestione degli input attraverso variabili superglobali:</li><li><code>&lt;strong&gt;$_COOKIE&lt;/strong&gt;</code>: deserializza e fornisce un accesso ai cookie Http.</li><li><code>&lt;strong&gt;$_GET&lt;/strong&gt;</code>: deserializza e fornisce un accesso agli argomenti della query string.</li><li><strong><code>$_POST</code></strong>: deserializza e fornisce un accesso per i parametri inviati tramite. Post Http. Può essere considerato il risultato dell&#8217;analisi del message body.</li><li><strong><code>$_FILES</code></strong>: fornisce metadati relativi ai caricamenti dei file.</li><li><strong><code>$_SERVER</code></strong>: fornisce l&#8217;accesso alle variabili d&#8217;ambiente CGI / SAPI che includono il metodo di richiesta, lo schema di richiesta, l&#8217;URI della richiesta e le intestazioni.</li></ul>



<p><strong><code>ServerRequestInterface</code></strong> estende <strong><code>RequestInterface</code></strong> per fornire un&#8217;astrazione su questi variabili superglobali riducendo l&#8217;accoppiamento.<br /><br />La richiesta server-side fornisce una proprietà aggiuntiva,  gli &#8220;attributi&#8221;, che consentono di esaminare, scompore e cercare match in modo da interpretare la richiesta in base alle specifiche necessità nell&#8217;applicativo.</p>



<h3 class="wp-block-heading">Upload dei file</h3>



<p><code>&lt;strong&gt;ServerRequestInterface&lt;/strong&gt;</code> specifica un metodo per recuperare una rappresentazione dei file caricati attraverso una struttura normalizzata in cui ogni elemento è un&#8217;istanza di <code>&lt;strong&gt;UploadedFileInterface&lt;/strong&gt;</code>.</p>



<p><strong><code>$_FILES</code></strong> ha alcuni problemi noti, ad esempio se si tenta di inviare da un form molteplici file attraverso campi di input aventi name &#8220;files&#8221;, l&#8217;array risultante verrà così rappresentato da PHP:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array(
    'files' =&gt; array(
        'name' =&gt; array(
            0 =&gt; 'file0.txt',
            1 =&gt; 'file1.html',
        ),
        'type' =&gt; array(
            0 =&gt; 'text/plain',
            1 =&gt; 'text/html',
        ),
        /* etc. */
    ),
)
</pre></div>


<p>Mentre ci si aspetterebbe una rappresentazione di questo tipo:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array(
    'files' =&gt; array(
        0 =&gt; array(
            'name' =&gt; 'file0.txt',
            'type' =&gt; 'text/plain',
            /* etc. */
        ),
        1 =&gt; array(
            'name' =&gt; 'file1.html',
            'type' =&gt; 'text/html',
            /* etc. */
        ),
    ),
)
</pre></div>


<p>Gli utilizzatori devono conoscere quindi i dettagli dell&#8217;implementazione nel linguaggio PHP e scrivere il codice per interpretare correttamente i dati di un determinato caricamento. </p>



<p>In alcuni casi poi <code>$_FILES</code> non viene popolato con i dati relativi ai file caricati:</p>



<ul><li>Quando il metodo Http non è POST.</li><li>Quando si esegue una unit test.</li><li>Quando si opera in un ambiente non SAPI come ad esempio ReactPHP.</li></ul>



<p>In questi casi si dovranno utilizzare approcci diversi, ad esempio:</p>



<ul><li>Un processo potrebbe analizzare il message body per scoprire i file caricati. </li><li>Negli scenari di unit test, gli sviluppatori devono essere in grado di bloccare e/o simulare i metadati di caricamento del file per convalidare e verificare i diversi scenari.</li></ul>



<p><code>&lt;strong&gt;getUploadedFiles()&lt;/strong&gt;</code> fornisce una struttura normalizzata e l&#8217;implementazione dovrebbe:</p>



<ul><li>Aggregare tutte le informazioni per un determinato caricamento di file e usarle per popolare un&#8217;istanza<code> &lt;strong&gt;Psr\Http\Message\UploadedFileInterface&lt;/strong&gt;</code>.</li><li>Ricreare la struttura ad albero inviata in cui ogni foglia rappresenti un&#8217;istanza di <code>&lt;strong&gt;Psr\Http\Message\UploadedFileInterface&lt;/strong&gt;</code> appropriata.</li><li>La struttura ad albero dovrebbe seguire la struttura dei nomi in cui sono stati inviati i file.</li></ul>



<p>Vediamo un esempio con un singolo campo di input con un &#8220;name semplice&#8221;:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: xml; gutter: false; title: ; notranslate">
&lt;input type=&quot;file&quot; name=&quot;avatar&quot; /&gt;
</pre></div>


<p>In questo caso, la struttura di $ _FILES sarebbe:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array(
    'avatar' =&gt; array(
        'tmp_name' =&gt; 'phpUxcOty',
        'name' =&gt; 'my-avatar.png',
        'size' =&gt; 90996,
        'type' =&gt; 'image/png',
        'error' =&gt; 0,
    ),
)
</pre></div>


<p>Mentre la forma normalizzata restituita da <code>getUploadedFiles()</code> potrebbe essere:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array(
    'avatar' =&gt; /* UploadedFileInterface instance */
)
</pre></div>


<p>Vediamo invece un caso di campo di input che utilizza crea un array nell&#8217;attributo nome:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: xml; gutter: false; title: ; notranslate">
&lt;input type=&quot;file&quot; name=&quot;my-form&#x5B;details]&#x5B;avatar]&quot; /&gt;
</pre></div>


<p>In questo caso il contenuto di $_FILES sarà</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array (
    'my-form' =&gt; array (
        'name' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; 'my-avatar.png',
            ),
        ),
        'type' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; 'image/png',
            ),
        ),
        'tmp_name' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; 'phpmFLrzD',
            ),
        ),
        'error' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; 0,
            ),
        ),
        'size' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; 90996,
            ),
        ),
    ),
)
</pre></div>


<p>E l&#8217;albero corrispondente restituito da <code>getUploadedFiles()</code> dovrebbe essere:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array(
    'my-form' =&gt; array(
        'details' =&gt; array(
            'avatar' =&gt; /* UploadedFileInterface instance */
        ),
    ),
)
</pre></div>


<p>Vediamo ora il caso di un array di file:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: xml; gutter: false; title: ; notranslate">
Upload an avatar: &lt;input type=&quot;file&quot; name=&quot;my-form&#x5B;details]&#x5B;avatars]&#x5B;]&quot; /&gt;
Upload an avatar: &lt;input type=&quot;file&quot; name=&quot;my-form&#x5B;details]&#x5B;avatars]&#x5B;]&quot; /&gt;
</pre></div>


<p>Ecco cosa conterrà <code>$_FILES</code>:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array (
    'my-form' =&gt; array (
        'name' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; array (
                    0 =&gt; 'my-avatar.png',
                    1 =&gt; 'my-avatar2.png',
                    2 =&gt; 'my-avatar3.png',
                ),
            ),
        ),
        'type' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; array (
                    0 =&gt; 'image/png',
                    1 =&gt; 'image/png',
                    2 =&gt; 'image/png',
                ),
            ),
        ),
        'tmp_name' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; array (
                    0 =&gt; 'phpmFLrzD',
                    1 =&gt; 'phpV2pBil',
                    2 =&gt; 'php8RUG8v',
                ),
            ),
        ),
        'error' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; array (
                    0 =&gt; 0,
                    1 =&gt; 0,
                    2 =&gt; 0,
                ),
            ),
        ),
        'size' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; array (
                    0 =&gt; 90996,
                    1 =&gt; 90996,
                    3 =&gt; 90996,
                ),
            ),
        ),
    ),
)
</pre></div>


<p>L&#8217;array sopra riportato corrisponderebbe alla seguente struttura restituita da <code>&lt;strong&gt;getUploadedFiles()&lt;/strong&gt;</code>:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array(
    'my-form' =&gt; array(
        'details' =&gt; array(
            'avatars' =&gt; array(
                0 =&gt; /* UploadedFileInterface instance */,
                1 =&gt; /* UploadedFileInterface instance */,
                2 =&gt; /* UploadedFileInterface instance */,
            ),
        ),
    ),
)
</pre></div>


<p>Per accedere all&#8217;elemento [1]:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
$request-&gt;getUploadedFiles()&#x5B;'my-form']&#x5B;'details']&#x5B;'avatars']&#x5B;1];
</pre></div>


<p>Seguendo il nostro esempio avremo:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
$file0 = $request-&gt;getUploadedFiles()&#x5B;'files']&#x5B;0];
$file1 = $request-&gt;getUploadedFiles()&#x5B;'files']&#x5B;1];

printf(
    &quot;Received the files %s and %s&quot;,
    $file0-&gt;getClientFilename(),
    $file1-&gt;getClientFilename()
);
</pre></div>


<p>Poiché le inforazioni sui file caricati, oltre che da <code>$_FILES</code>, possono derivare da altri elementi della richiesta,  è presente il metodo <code>&lt;strong&gt;withUploadedFiles()&lt;/strong&gt;</code> che consente di delegare la normalizzazione ad un altro processo.</p>



<p>Lo standard PSR-7 considera anche le implementazioni in ambienti non SAPI. Pertanto, <code>UploadedFileInterface</code> fornisce metodi per garantire che le operazioni funzionino indipendentemente dall&#8217;ambiente. In particolare:</p>



<ul><li><strong><code>moveTo($targetPath)</code></strong> viene fornito come alternativa sicura e consigliata per richiamare <code>move_uploaded_file()</code> sul file di caricamento temporaneo. Le implementazioni rileveranno il corretto funzionamento da utilizzare in base all&#8217;ambiente.</li><li><code>&lt;strong&gt;getStream()&lt;/strong&gt;</code> restituirà un&#8217;istanza <code>StreamInterface</code>. In ambienti non SAPI, una possibilità proposta è quella di eseguire il parsing dei file caricati nello stream <code>php://temp</code>.</li></ul>



<p>Ad esempio:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
// Move a file to an upload directory
$filename = sprintf(
    '%s.%s',
    create_uuid(),
    pathinfo($file0-&gt;getClientFilename(), PATHINFO_EXTENSION)
);
$file0-&gt;moveTo(DATA_DIR . '/' . $filename);

// Stream a file to Amazon S3.
// Assume $s3wrapper is a PHP stream that will write to S3, and that
// Psr7StreamWrapper is a class that will decorate a StreamInterface as a PHP
// StreamWrapper.
$stream = new Psr7StreamWrapper($file1-&gt;getStream());
stream_copy_to_stream($stream, $s3wrapper);
</pre></div>


<h2 class="wp-block-heading">PSR-7: Interfacce</h2>



<h3><a name="MessageInterface"></a>Psr\Http\Message\MessageInterface</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
interface MessageInterface {
    /**
     * Recupera la versione del protocollo HTTP (Es: &quot;1.1&quot;, &quot;1.0&quot;)
     *
     * @return string HTTP protocol version.
     */
    public function getProtocolVersion();

    /**
     * Restituisce un'istanza con una specifica versione del protocollo HTTP
     *
     * @param string $version HTTP protocol version
     * @return static
     */
    public function withProtocolVersion($version);

    /**
     * Recupera tutti i valori di intestazione del messaggio
     *
     * @return string&#x5B;]&#x5B;] Returns an associative array of the message's headers.
     */
    public function getHeaders();

    /**
     * Verifica se esiste un'intestazione in base al nome senza distinzione tra maiuscole e minuscole.
     *
     * @param string $name Case-insensitive header field name.
     * @return bool
     */
    public function hasHeader($name);

    /**
     * Recupera un valore di intestazione del messaggio in base al nome senza distinzione tra maiuscole e minuscole.
     *
     * @param string $name Case-insensitive header field name.
     * @return string&#x5B;] An array of string values as provided for the given header.
     */
    public function getHeader($name);

    /**
     * Recupera una stringa separata da virgole dei valori per una singola intestazione.
     *
     * @param string $name Case-insensitive header field name.
     * @return string A string of values as provided for the given header concatenated together using a comma.
     */
    public function getHeaderLine($name);

    /**
     * Restituisce un'istanza sostituendo il valore dell'intestazione specificata.
     *
     * @param string $name Case-insensitive header field name.
     * @param string|string&#x5B;] $value Header value(s).
     * @return static
     * @throws \InvalidArgumentException for invalid header names or values.
     */
    public function withHeader($name, $value);

    /**
     * Restituisce un'istanza appendendo un valore al campo di intestazione specificato.
     *
     * @param string $name Case-insensitive header field name to add.
     * @param string|string&#x5B;] $value Header value(s).
     * @return static
     * @throws \InvalidArgumentException for invalid header names or values.
     */
    public function withAddedHeader($name, $value);

    /**
     * Restituisce un'istanza eliminando l'intestazione specificata.
     *
     * @param string $name Case-insensitive header field name to remove.
     * @return static
     */
    public function withoutHeader($name);

    /**
     * Ottiene il corpo del messaggio.
     *
     * @return StreamInterface Returns the body as a stream.
     */
    public function getBody();

    /**
     * Restituisce un'istanza con il corpo del messaggio specificato.
     *   
     * @param StreamInterface $body Body.
     * @return static
     * @throws \InvalidArgumentException When the body is not valid.
     */
    public function withBody(StreamInterface $body);
}
</pre></div>


<p></p>
<p>L'articolo <a href="https://www.cesarebordi.it/psr-7-http-message-standard-php-request-response/">PSR-7 Http Message: standard php per Request e Response.</a> sembra essere il primo su <a href="https://www.cesarebordi.it">Cesare Bordi | Innovation Manager &amp; Back-end Developer</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cesarebordi.it/psr-7-http-message-standard-php-request-response/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
