Entorno de Consulta

Cada petición HTTP (normalmente originada por un navegador) contiene información adicional sobre la petición, tal como datos de cabecera, archivos, variables, etcétera. Una aplicación basada en web necesita analizar esa información para proporcionar la respuesta correcta al solicitante. Phalcon\Http\Request encapsula la información de la solicitud, lo que le permite acceder de una manera orientada a objetos.

<?php

use Phalcon\Http\Request;

// Obteniendo una instancia de la consulta
$request = new Request();

// Comprobar que la consulta este hecha por el método POST
if ($request->isPost()) {
    // Comprobar si la consulta esta hecha con Ajax
    if ($request->isAjax()) {
        echo 'La consulta fue hecha utilizando POST y AJAX';
    }
}

Obteniendo Valores

PHP automáticamente llena los arreglos superglobales $_GET y $_POST dependiendo del tipo de solicitud. Estos arrays contienen los valores presentes en los formularios o los parámetros enviados por la URL. Las variables en las matrices no son desinfectadas y puede contener caracteres ilegales o incluso códigos malintencionados, que pueden conducir a la inyección de SQL o ataques de Cross Site Scripting (XSS).

Phalcon\Http\Request le permite acceder a los valores almacenados en $_REQUEST, $_GET y $_POST y desinfectarlos o filtrarlos con el servicio filter, (por defecto Phalcon\Filter). Los siguientes ejemplos ofrecen el mismo comportamiento:

<?php

use Phalcon\Filter;

$filter = new Filter();

// Filtros aplicados manualmente
$email = $filter->sanitize($_POST['user_email'], 'email');

// Aplicando manualmente el filtro a un valor
$email = $filter->sanitize($request->getPost('user_email'), 'email');

// Aplicar automáticamente el filtro
$email = $request->getPost('user_email', 'email');

// Establecer un valor por defecto si el parámetro es nulo
$email = $request->getPost('user_email', 'email', '[email protected]');

// Estableciendo un valor por defeccto si el parámetro es nulo sin filtrado
$email = $request->getPost('user_email', null, '[email protected]');

Accediendo a la Consulta desde los Controladores

El lugar más común para acceder el ambiente de la petición es en una acción de un controlador. Para tener acceso al objeto Phalcon\Http\Request desde un controlador necesita utilizar la propiedad pública $this->request del controlador:

<?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function indexAction()
    {

    }

    public function saveAction()
    {
        // Comprobar si la consulta fue hecha con POST
        if ($this->request->isPost()) {
            // Acceder a los datos POST
            $customerName = $this->request->getPost('name');
            $customerBorn = $this->request->getPost('born');
        }
    }
}

Subiendo Archivos

Otra tarea común es la subida de archivos. Phalcon\Http\Request ofrece una forma orientada a objetos para realizar esta tarea:

<?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function uploadAction()
    {
        // Comprobar si el usuario ha subido archivos
        if ($this->request->hasFiles()) {
            $files = $this->request->getUploadedFiles();

            // Imprimir el nombre real y el tamaño del archivo
            foreach ($files as $file) {
                // Imprimir detalles del archivo
                echo $file->getName(), ' ', $file->getSize(), '\n';

                // Mover el archivo dentro de la aplicación
                $file->moveTo(
                    'files/' . $file->getName()
                );
            }
        }
    }
}

Cada objeto retornado por Phalcon\Http\Request::getUploadedFiles() es una instancia de la clase Phalcon\Http\Request\File. Utilizar el arreglo superglobal $_FILES ofrece el mismo comportamiento. Phalcon\Http\Request\File encapsula solo la información relacionada con cada archivo subido en la consulta.

Trabajando con Cabeceras

Como se mencionó anteriormente, los encabezados de la solicitud contienen información útil que nos permite dar la respuesta adecuada al usuario. Los siguientes ejemplos muestran los usos de esa información:

<?php

// Obtener la cabecera Http-X-Requested-With
$requestedWith = $request->getHeader('HTTP_X_REQUESTED_WITH');

if ($requestedWith === 'XMLHttpRequest') {
    echo 'La consulta fue hecha con Ajax';
}

// Igual que lo anterior
if ($request->isAjax()) {
    echo 'La consulta fue hecha con Ajax';
}

// Comprobar la capa de la consulta
if ($request->isSecure()) {
    echo 'La consulta fue hecha utilizando una capa de seguridad';
}

// Obtener la dirección IP del servidor. Por ejemplo: 192.168.0.100
$ipAddress = $request->getServerAddress();

// Obtener la dirección IP del cliente. Por ejemplo: 201.245.53.51
$ipAddress = $request->getClientAddress();

// Obtener el agente del usuario (HTTP_USER_AGENT)
$userAgent = $request->getUserAgent();

// Obtener el mejor contenido aceptable por el navegador. Por ejemplo: text/xml
$contentType = $request->getAcceptableContent();

// Obtener el mejor conjunto de caracteres aceptados por el navegador. Por ejemplo: utf-8
$charset = $request->getBestCharset();

// Obtener el mejor idioma aceptado configurado por el navegador. Por ejemplo: en-us
$language = $request->getBestLanguage();

// Comprueba si existe una cabecera
if ($request->hasHeader('my-header')) {
    echo "María tenia un corderito";
}

Eventos

Cuando usamos la autorización HTTP, la cabecera Authorization tiene el siguiente formato:

Authorization: <type> <credentials>

donde <type> es un tipo de autenticación. El tipo común es Basic. Los tipos adicionales de autenticación están en el Registro IANA de esquemas de autenticación y Autenticación para los servidores AWS (AWS4-HMAC-SHA256). En el 99.99% de los casos los tipos de autenticación son:

  • AWS4-HMAC-SHA256
  • Basic
  • Bearer
  • Digest
  • HOBA
  • Mutual
  • Negotiate
  • OAuth
  • SCRAM-SHA-1
  • SCRAM-SHA-256
  • vapid

Se pueden utilizar los eventos request:beforeAuthorizationResolve y request:afterAuthorizationResolve para realizar operaciones adicionales antes o después de las resoluciones de autorización. Se requiere una resolución de autorizaciones personalizada.

Un ejemplo sin usar el solucionador de autorizaciones personalizado:

<?php

use Phalcon\Http\Request;

$_SERVER['HTTP_AUTHORIZATION'] = 'Enigma Secret';

$request = new Request();
print_r($request->getHeaders());

Resultado:

Array
(
    [Authorization] => Enigma Secret
)

Type: Enigma
Credentials: Secret

Un ejemplo usando el solucionador de autorizaciones personalizado:

<?php

use Phalcon\Di;
use Phalcon\Events\Event;
use Phalcon\Http\Request;
use Phalcon\Events\Manager;

class NegotiateAuthorizationListener
{
    public function afterAuthorizationResolve(Event $event, Request $request, array $data)
    {
        if (empty($data['server']['CUSTOM_KERBEROS_AUTH'])) {
            return false;
        }

        list($type,) = explode(' ', $data['server']['CUSTOM_KERBEROS_AUTH'], 2);

        if (!$type || stripos($type, 'negotiate') !== 0) {
            return false;
        }

        return [
           'Authorization'=> $data['server']['CUSTOM_KERBEROS_AUTH'],
        ];
    }
}

$_SERVER['CUSTOM_KERBEROS_AUTH'] = 'Negotiate a87421000492aa874209af8bc028';

$di = new Di();

$di->set('eventsManager', function () {
    $manager = new Manager();
    $manager->attach('request', new NegotiateAuthorizationListener());

    return $manager;
});

$request = new Request();
$request->setDI($di);

print_r($request->getHeaders());

Resultado:

Array
(
    [Authorization] => Negotiate a87421000492aa874209af8bc028
)

Type: Negotiate
Credentials: a87421000492aa874209af8bc028