Saltar al contenido

PHP “php: // input” frente a $ _POST

Solución:

La razon es que php://input devuelve todos los datos sin procesar después de los encabezados HTTP de la solicitud, independientemente del tipo de contenido.

El PHP superglobal $_POST, solamente se supone que es envolver datos que son

  • application/x-www-form-urlencoded (tipo de contenido estándar para publicaciones de formularios simples) o
  • multipart/form-data (utilizado principalmente para cargar archivos)

Esto se debe a que estos son los únicos tipos de contenido que debe ser apoyado por agentes de usuario. Por lo tanto, el servidor y PHP tradicionalmente no esperan recibir ningún otro tipo de contenido (lo que no significa que no puedan).

Entonces, si simplemente PUBLICA un buen HTML antiguo form, la solicitud se parece a esto:

POST /page.php HTTP/1.1

key1=value1&key2=value2&key3=value3

Pero si está trabajando mucho con Ajax, esta probabilidad también incluye el intercambio de datos más complejos con tipos (string, En t, bool) y estructuras (matrices, objetos), por lo que, en la mayoría de los casos, JSON es la mejor opción. Pero una solicitud con una carga útil JSON se vería así:

POST /page.php HTTP/1.1

"key1":"value1","key2":"value2","key3":"value3"

El contenido ahora sería application/json (o al menos ninguno de los mencionados anteriormente), por lo que PHP $_POST-wrapper no sabe cómo manejar eso (todavía).

Los datos todavía están allí, simplemente no puede acceder a ellos a través del contenedor. Por lo tanto, debe buscarlo usted mismo en formato sin procesar con file_get_contents('php://input') (siempre que no sea multipart/form-data-codificado).

También es así como accedería a datos XML o cualquier otro tipo de contenido no estándar.

php://input puede darle los bytes sin procesar de los datos. Esto es útil si los datos POSTed son una estructura codificada JSON, que suele ser el caso de una solicitud POST AJAX.

Aquí hay una función para hacer precisamente eso:

  /**
   * Returns the JSON encoded POST data, if any, as an object.
   * 
   * @return Object|null
   */
  private function retrieveJsonPostData()
  
    // get the raw POST data
    $rawData = file_get_contents("php://input");

    // this returns null if not valid json
    return json_decode($rawData);
  

los $_POST array es más útil cuando manejas key-valor de datos de un formulario, enviado por un POST tradicional. Esto solo funciona si los datos POSTED están en un formato reconocido, generalmente application/x-www-form-urlencoded (consulte http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 para obtener más detalles).

Primero, una verdad básica sobre PHP.

PHP no fue diseñado para brindarle explícitamente una interfaz de tipo REST (GET, POST, PUT, PATCH, DELETE) pura para manejar solicitudes HTTP.

sin embargo, el $_SERVER, $_COOKIE, $_POST, $_GET, y $_FILES superglobales, y la función filter_input_array() son muy útiles para las necesidades de la persona promedio / lego.

La ventaja oculta número uno de $_POST (y $_GET) es que sus datos de entrada son url-decodificado automáticamente por PHP. Ni siquiera piensas en tener que hacerlo, especialmente para consultas. string parámetros dentro de un estándar GET solicitud, o datos del cuerpo HTTP enviados con un POST solicitud.

Otros métodos de solicitud HTTP

Aquellos que estudian el protocolo HTTP subyacente y sus diversos métodos de solicitud llegan a comprender que existen muchos métodos de solicitud HTTP, incluido el que a menudo se hace referencia PUT, PATCH (no se utiliza en Apigee de Google) y DELETE.

En PHP, no hay superglobales o funciones de filtro de entrada para obtener datos del cuerpo de la solicitud HTTP cuando POST no se utiliza. ¿Qué deben hacer los discípulos de Roy Fielding? 😉

Sin embargo, luego aprende más …

Dicho esto, a medida que avanza en sus conocimientos de programación PHP y desea utilizar JavaScript XmlHttpRequest object (jQuery para algunos), llega a ver la limitación de este esquema.

$_POST le limita al uso de dos tipos de medios en HTTP Content-Type encabezamiento:

  1. application/x-www-form-urlencoded, y
  2. multipart/form-data

Por lo tanto, si desea enviar valores de datos a PHP en el servidor y hacer que se muestren en el $_POST superglobal, luego debe codificarlo con urlen en el lado del cliente y enviar dichos datos como key/ pares de valores: un paso inconveniente para los principiantes (especialmente cuando se trata de averiguar si diferentes partes de la URL requieren diferentes formas de codificación urlen: normal, sin procesar, etc.).

Para todos los usuarios de jQuery, $.ajax() El método es convertir su JSON a URL codificado. keypares / valor antes de transmitirlos al servidor. Puede anular este comportamiento configurando processData: false. Simplemente lea la documentación de $ .ajax () y no olvide enviar el tipo de medio correcto en el encabezado Content-Type.

php: // entrada, pero …

Incluso si usa php://input en lugar de $_POST para tu HTTP POST solicitar datos corporales, no trabajo con un HTTP Content-Type de multipart/form-data Este es el tipo de contenido que usa en un formulario HTML cuando desea permitir la carga de archivos.

Por lo tanto, en PHP tradicional, para tratar con una diversidad de tipos de contenido desde un HTTP POST solicitud, aprenderá a usar $_POST o filter_input_array(POST), $_FILES, y php://input. No hay forma de usar solo una fuente de entrada universal para HTTP POST solicitudes en PHP.

No puede pasar archivos $_POST, filter_input_array (POST), o php://input, y no puede obtener JSON / XML / YAML en ninguno de los dos filter_input_array(POST) o $_POST.

Manual de PHP: php: // entrada

php: // input es un flujo de solo lectura que le permite leer datos sin procesar del cuerpo de solicitud… php: // la entrada es No disponible con enctype = “multipart / form-data”.

¿PHP Frameworks al rescate?

Los frameworks PHP como Codeigniter 4 y Laravel usan una fachada para proporcionar una interfaz más limpia (IncomingRequest o Request objetos) a lo anterior. Esta es la razón por la que los desarrolladores de PHP profesionales usan frameworks en lugar de PHP sin formato.

Por supuesto, si le gusta programar, puede diseñar su propio objeto de fachada para proporcionar lo que hacen los marcos. Es porque me he tomado el tiempo para investigar este problema que puedo escribir esta respuesta.

Codificación de URL? ¿¿¿¡¡¡Que demonios!!!???

Por lo general, si realiza una solicitud HTTP normal y sincrónica (cuando se vuelve a dibujar toda la página) con un formulario HTML, el agente de usuario (navegador web) codificará los datos del formulario por usted. Si desea realizar solicitudes HTTP asincrónicas utilizando el XmlHttpRequest objeto, entonces debe crear un código urlencoded string y envíalo, si desea que esos datos aparezcan en el $_POST superglobal.

¿Cómo estás en contacto con JavaScript? 🙂

Conversión de JavaScript array u objetar a un código urlencoded string molesta a muchos desarrolladores (incluso con nuevas API como Form Data). Preferirían poder enviar JSON, y sería más eficiente para que el código de cliente lo haga.

Recuerde (guiño, guiño), el desarrollador web promedio no aprende a usar el XmlHttpRequest objeto directamente, funciones globales, string funciones, array funciones y expresiones regulares como tú y yo ;-). Urlencoding para ellos es una pesadilla. 😉

PHP, ¿qué pasa?

La falta de PHP de manejo intuitivo de XML y JSON apaga a muchas personas. Pensarías que ahora sería parte de PHP (suspiro).

Tantos tipos de medios (tipos MIME en el pasado)

XML, JSON y YAML tienen tipos de medios que se pueden colocar en un HTTP Content-Type encabezamiento.

  • aplicación / xml
  • aplicación / json
  • application / yaml (aunque IANA no tiene una designación oficial en la lista)

Mire cuántos tipos de medios (anteriormente, tipos MIME) define IANA.

Mira cuántos encabezados HTTP hay.

php: // entrada o busto

Utilizando el php://input stream le permite eludir el nivel de abstracción de niñera / agarre de la mano que PHP ha impuesto al mundo. 🙂 ¡Con un gran poder viene una gran responsabilidad!

Ahora, antes de lidiar con los valores de datos transmitidos php://input, debes / debes hacer algunas cosas.

  1. Determine si el correcto Método HTTP se ha indicado (GET, POST, PUT, PATCH, DELETE, …)
  2. Determine si el HTTP Tipo de contenido Se ha transmitido el encabezado.
  3. Determine si el valor para Content-Type es el tipo de medio deseado.
  4. Determinar si los datos enviados son bien formado XML / JSON / YAML / etc.
  5. Si necesario, convertir los datos a un tipo de datos PHP: array u objeto.
  6. Si alguna de estas comprobaciones o conversiones básicas falla, lanza una excepción!

¿Qué pasa con la codificación de caracteres?

¡AH, JA! Sí, es posible que desee que el flujo de datos que se envía a su aplicación esté codificado en UTF-8, pero ¿cómo puede saber si lo está o no?

Dos problemas críticos.

  1. No sabe cuántos datos están llegando php://input.
  2. No conoce con certeza la codificación actual del flujo de datos.

¿Intentará manejar datos de flujo sin saber cuánto hay primero? Esa es una idea terrible. No puede confiar exclusivamente en HTTP Content-Length encabezado para obtener orientación sobre el tamaño de la entrada transmitida, ya que se puede falsificar.

Vas a necesitar un:

  1. Algoritmo de detección de tamaño de flujo.
  2. Límites de tamaño de transmisión definidos por la aplicación (los límites de Apache / Nginx / PHP pueden ser demasiado amplios).

¿Va a intentar convertir datos de transmisión a UTF-8 sin conocer la codificación actual de la transmisión? ¿Cómo? El filtro de flujo iconv (ejemplo de filtro de flujo iconv) parece querer una codificación inicial y final, como esta.

'convert.iconv.ISO-8859-1/UTF-8'

Por lo tanto, si es concienzudo, necesitará:

  1. Algoritmo de detección de codificación de flujo.
  2. Algoritmo de definición de filtro de flujo dinámico / en tiempo de ejecución (porque no puede conocer la codificación inicial a priori).

(Actualizar: 'convert.iconv.UTF-8/UTF-8' forzará todo a UTF-8, pero aún debe tener en cuenta los caracteres que la biblioteca iconv podría no saber cómo traducir. En otras palabras, tiene que definir de alguna manera qué acción tomar cuando un carácter no se puede traducir: 1) Insertar un carácter ficticio, 2) Fallar / lanzar y excepción).

No puede confiar exclusivamente en HTTP Content-Encoding encabezado, ya que esto podría indicar algo así como compresión como en el siguiente. Esto no es lo que quiere tomar una decisión con respecto a iconv.

Content-Encoding: gzip

Por lo tanto, los pasos generales pueden ser …

Parte I: Solicitud HTTP relacionada

  1. Determine si el correcto Método HTTP se ha indicado (GET, POST, PUT, PATCH, DELETE, …)
  2. Determine si el HTTP Tipo de contenido encabezamiento ha sido transmitido.
  3. Determine si el valor para Content-Type es el tipo de medio deseado.

Parte II: Transmisión de datos relacionados

  1. Determine el tamaño del flujo de entrada (opcional, pero recomendado).
  2. Determine la codificación del flujo de entrada.
  3. Si es necesario, convierta el flujo de entrada a la codificación de caracteres deseada (UTF-8).
  4. Si es necesario, invierta cualquier compresión o cifrado a nivel de aplicación y luego repita los pasos 4, 5 y 6.

Parte III: Relacionado con el tipo de datos

  1. Determinar si los datos enviados son bien formado XML / JSON / YMAL / etc.

(Recuerde, los datos aún pueden ser una URL codificada string que luego debe analizar y decodificar la URL).

  1. Si necesario, convertir los datos a un tipo de datos PHP: array u objeto.

Parte IV: Relacionado con el valor de los datos

  1. Filtrar datos de entrada.

  2. Validar los datos de entrada.

Ahora ves?

los $_POST superglobal, junto con la configuración de php.ini para los límites de entrada, son más simples para el profano. Sin embargo, lidiar con la codificación de caracteres es mucho más intuitivo y eficiente cuando se utilizan transmisiones porque no hay necesidad de recorrer superglobales (o matrices, en general) para verificar los valores de entrada para la codificación adecuada.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *