When writing middleware-based applications, at some point you will need to emit your response.

PSR-7 defines the various interfaces related to HTTP messages, but does not define how they will be used. Diactoros defines several utility classes for these purposes, including a ServerRequestFactory for generating a ServerRequest instance from the PHP SAPI in use, and a set of emitters, for emitting responses back to the client. In this post, we'll detail the purpose of emitters, the emitters shipped with Diactoros, and some strategies for emitting content to your users.

What is an emitter?

In vanilla PHP applications, you might call one or more of the following functions in order to provide a response to your client:

  • http_response_code() for emitting the HTTP response code to use; this must be called before any output is emitted.
  • header() for emitting response headers. Like http_response_code(), this must be called before any output is emitted. It may be called multiple times, in order to set multiple headers.
  • echo(), printf(), var_dump(), and var_export() will each emit output to the current output buffer, or, if none is present, directly to the client.

One aspect PSR-7 aims to resolve is the ability to generate a response piece-meal, including adding content and headers in whatever order your application requires. To accomplish this, it provides a ResponseInterface with which your application interacts, and which aggregates the response status code, its headers, and all content.

Once you have a complete response, however, you need to emit it.

Diactoros provides emitters to solve this problem. Emitters all implement Zend\Diactoros\Response\EmitterInterface:

namespace Zend\Diactoros\Response;

use Psr\Http\Message\ResponseInterface;

interface EmitterInterface
{
    /**
     * Emit a response.
     *
     * Emits a response, including status line, headers, and the message body,
     * according to the environment.
     *
     * Implementations of this method may be written in such a way as to have
     * side effects, such as usage of header() or pushing output to the
     * output buffer.
     *
     * Implementations MAY raise exceptions if they are unable to emit the
     * response; e.g., if headers have already been sent.
     *
     * @param ResponseInterface $response
     */
    public function emit(ResponseInterface $response);
}

Diactoros provides two emitter implementations, both geared towards standard PHP SAPI implementations:

  • Zend\Diactoros\Emitter\SapiEmitter
  • Zend\Diactoros\Emitter\SapiStreamEmitter

Internally, they operate very similarly: they emit the response status code, all headers, and the response body content. Prior to doing so, however, they check for the following conditions:

  • Headers have not yet been sent.
  • If any output buffers exist, no content is present.

If either of these conditions is not true, the emitters raise an exception. This is done to ensure that consistent content can be emitted; mixing PSR-7 and global output leads to unexpected and inconsistent results. If you are using middleware, use things like the error log, loggers, etc. if you want to debug, instead of mixing strategies.

Emitting files

As noted above, one of the two emitters is the SapiStreamEmitter. The normal SapiEmitter emits the response body at once via a single echo statement. This works for most general markup and JSON payloads, but when returning files (for example, when providing file downloads via your application), this strategy can quickly exhaust the amount of memory PHP is allowed to consume.

The SapiStreamEmitter is designed to answer the problem of file downloads. It emits a chunk at a time (8192 bytes by default). While this can mean a bit more performance overhead when emitting a large file, as you'll have more method calls, it also leads to reduced memory overhead, as less content is in memory at any given time.

The SapiStreamEmitter has another important feature, however: it allows sending content ranges.

Clients can opt-in to receiving small chunks of a file at a time. While this means more network calls, it can also help prevent corruption of large files by allowing the client to re-try failed requests in order to stitch together the full file. Doing so also allows providing progress status, or even buffering streaming content.

When requesting content ranges, the client will pass a Range header:

Range: bytes=1024-2047

It is up to the server then to detect such a header and return the requested range. Servers indicate that they are doing so by responding with a Content-Range header with the range of bytes being returned and the total number of bytes possible; the response body then only contains those bytes.

Content-Range: bytes=1024-2047/11576

As an example, middleware that allows returning a content range might look like the following:

function (ServerRequestInterface $request, DelegateInterface $delegate) : ResponseInterface
{
    $stream = new Stream('path/to/download/file', 'r');
    $response = new Response($stream);

    $range = $request->getHeaderLine('range');
    if (empty($range)) {
        return $response;
    }

    $size  = $body->getSize();
    $range = str_replace('=', ' ', $range);
    $range .= '/' . $size;

    return $response->withHeader('Content-Range', $range);
}

You'll likely want to validate that the range is within the size of the file, too!

The above code emits a Content-Range response header if a Range header is in the request. However, how do we ensure only that range of bytes is emitted?

By using the SapiStreamEmitter! This emitter will detect the Content-Range header and use it to read and emit only the bytes specified by that header; no extra work is necessary!

Mixing and matching emitters

The SapiEmitter is perfect for content generated within your application — HTML, JSON, XML, etc. — as such content is usually of reasonable length, and will not exceed normal memory and resource limits.

The SapiStreamEmitter is ideal for returning file downloads, but can lead to performance overhead when emitting standard application content.

How can you mix and match the two?

Expressive answers this question by providing Zend\Expressive\Emitter\EmitterStack. The class acts as a stack (last in, first out), executing each emitter composed until one indicates it has handled the response.

This class capitalizes on the fact that the return value of EmitterInterface is undefined. Emitters that return a boolean false indicate they were unable to handle the response, allowing the EmitterStack to move to the next emitter in the stack. The first emitter to return a non-false value halts execution.

Both the emitters defined in zend-diactoros return null by default. So, if we want to create a stack that first tries SapiStreamEmitter, and then defaults to SapiEmitter, we could do the following:

use Psr\Http\Message\ResponseInterface;
use Zend\Diactoros\Response\EmitterInterface;
use Zend\Diactoros\Response\SapiEmitter;
use Zend\Diactoros\Response\SapiStreamEmitter;
use Zend\Expressive\Emitter\EmitterStack;

$emitterStack = new EmitterStack();
$emitterStack->push(new SapiEmitter());
$emitterStack->push(new class implements EmitterInterface {
    public function emit(ResponseInterface $response)
    {
        $contentSize = $response->getBody()->getSize();

        if ('' === $response->getHeaderLine('content-range')
            && $contentSize < 8192
        ) {
            return false;
        }

        $emitter = new SapiStreamEmitter();
        return $emitter->emit($response);
    }
});

The above will execute our anonymous class as the first emitter. If the response has a Content-Range header, or if the size of the content is greater than 8k, it will use the SapiStreamEmitter; otherwise, it returns false, allowing the next emitter in the stack, SapiEmitter, to execute. Since that emitter always returns null, it acts as a default emitter implementation.

In Expressive, if you were to wrap the above in a factory that returns the $emitterStack, and assign that factory to the Zend\Diactoros\Emitter\EmitterInterface service, then the above stack will be used by Zend\Expressive\Application for the purpose of emitting the application response!

Summary

Emitters provide you the ability to return the response you have aggregated in your application to the client. They are intended to have side-effects: sending the response code, response headers, and body content. Different emitters can use different strategies when emitting responses, from simply echoing content, to iterating through chunks of content (as the SapiStreamEmitter does). Using Expressive's EmitterStack can provide you with a way to select different emitters for specific response criteria.

For more information:

Source

Every PHP application generates errors, warnings, and notices and throws exceptions. If we do not log this information, we lose a way to identify and solve problems at runtime. Moreover, we may need to log specific actions such as a user login and logout attempts. All such information should be filtered and stored in an efficient way.

PHP offers the function error_log() to send an error message to the defined system logger, and the function set_error_handler() to specify a handler for intercepting warnings, errors, and notices generated by PHP.

These functions can be used to customize error management, but it's up to the developer to write the logic to filter and store the data.

Zend Framework offers a logging component, zend-log; the library can be used as a general purpose logging system. It supports multiple log backends, formatting messages sent to the log, and filtering messages from being logged.

Last but not least, zend-log is compliant with PSR-3, the logger interface standard.

Installation

You can install zend-log using the following composer command:

composer require zendframework/zend-log

Usage

zend-log can be used to create log entries in different formats using multiple backends. You can also filter the log data from being saved, and process the log event prior to filtering or writing, allowing the ability to substitute, add, remove, or modify the data you log.

Basic usage of zend-log requires both a writer and a logger instance. A writer stores the log entry into a backend, and the logger consumes the writer to perform logging operations.

As an example:

use Zend\Log\Logger;
use Zend\Log\Writer\Stream;

$logger = new Logger;
$writer = new Stream('php://output');

$logger->addWriter($writer);
$logger->log(Logger::INFO, 'Informational message');

The above produces the following output:

2017-09-11T15:07:46+02:00 INFO (6): Informational message

The output is a string containing a timestamp, a priority (INFO (6)) and the message (Informational message). The output format can be changed using the setFormatter() method of the writer object ($writer). The default log format, produced by the Simple formatter is as follows:

%timestamp% %priorityName% (%priority%): %message% %extra%

where %extra% is an optional value containing additional information.

For instance, if you wanted to change the format to include only log %message%, you could do the following:

$formatter = new Zend\Log\Formatter\Simple('log %message%' . PHP_EOL);
$writer->setFormatter($formatter);

Log PHP events

zend-log can also be used to log PHP errors and exceptions. You can log PHP errors using the static method Logger::registerErrorHandler($logger) and intercept exceptions using the static method Logger::registerExceptionHandler($logger).

use Zend\Log\Logger;
use Zend\Log\Writer;

$logger = new Logger;
$writer = new Writer\Stream(__DIR__ . '/test.log');
$logger->addWriter($writer);

// Log PHP errors
Logger::registerErrorHandler($logger);

// Log exceptions
Logger::registerExceptionHandler($logger);

Filtering data

As mentioned, we can filter the data to be logged; filtering removes messages that match the filter criteria, preventing them from being logged.

We can use the addFilter() method of the Writer interface to add a specific filter.

For instance, we can filter by priority, accepting only log entries with a priority less than or equal to a specific value:

$filter = new Zend\Log\Filter\Priority(Logger::CRIT);
$writer->addFilter($filter);

In the above example, the logger will only store log entries with a priority less than or equal to Logger::CRIT (critical). The priorities are defined by the Zend\Log\Logger class:

const EMERG   = 0;  // Emergency: system is unusable
const ALERT   = 1;  // Alert: action must be taken immediately
const CRIT    = 2;  // Critical: critical conditions
const ERR     = 3;  // Error: error conditions
const WARN    = 4;  // Warning: warning conditions
const NOTICE  = 5;  // Notice: normal but significant condition
const INFO    = 6;  // Informational: informational messages
const DEBUG   = 7;  // Debug: debug messages

As such, only emergency, alerts, or critical entries would be logged.

We can also filter log data based on regular expressions, timestamps, and more. One powerful filter uses a zend-validator ValidatorInterface instance to filter the log; only valid entries would be logged in such cases.

Processing data

If you need to provide additional information to logs in an automated fashion, you can use a Zend\Log\Processer class. A processor is executed before the log data are passed to the writer. The input of a processor is a log event, an array containing all of the information to log; the output is also a log event, but can contain modified or additional values. A processor modifies the log event to prior to sending it to the writer.

You can read about processor adapters offered by zend-log in the documentation.

Multiple backends

One of the cool feature of zend-log is the possibility to write logs using multiple backends. For instance, you can write a log to both a file and a database using the following code:

use Zend\Db\Adapter\Adapter as DbAdapter;
use Zend\Log\Formatter;
use Zend\Log\Writer;
use Zend\Log\Logger;

// Create our adapter
$db = new DbAdapter([
    'driver'   => 'Pdo',
    'dsn'      => 'mysql:dbname=testlog;host=localhost',
    'username' => 'root',
    'password' => 'password'
]);

// Map event data to database columns
$mapping = [
    'timestamp' => 'date',
    'priority'  => 'type',
    'message'   => 'event',
];

// Create our database log writer
$writerDb = new Writer\Db($db, 'log', $mapping); // log table
$formatter = new Formatter\Base();
$formatter->setDateTimeFormat('Y-m-d H:i:s'); // MySQL DATETIME format
$writerDb->setFormatter($formatter);

// Create our file log writer
$writerFile = new Writer\Stream(__DIR__ . '/test.log');

// Create our logger and register both writers
$logger = new Logger();
$logger->addWriter($writerDb, 1);
$logger->addWriter($writerFile, 100);

// Log an information message
$logger->info('Informational message');

The database writer requires the credentials to access the table where you will store log information. You can customize the field names for the database table using a $mapping array, containing an associative array mapping log fields to database columns.

The database writer is composed in $writerDb and the file writer in $writerFile. The writers are added to the logger using the addWriter() method with a priority number; higher integer values indicate higher priority (triggered earliest). We chose priority 1 for the database writer, and priority 100 for the file writer; this means the file writer will log first, followed by logging to the database.

Note: we used a special date formatter for the database writer. This is required to translate the log timestamp into the DATETIME format of MySQL.

PSR-3 support

If you need to be compatible with PSR-3, you can use Zend\Log\PsrLoggerAdapter. This logger can be used anywhere a Psr\Log\LoggerInterface is expected.

As an example:

use Psr\Log\LogLevel;
use Zend\Log\Logger;
use Zend\Log\PsrLoggerAdapter;

$zendLogLogger = new Logger;
$psrLogger = new PsrLoggerAdapter($zendLogLogger);

$psrLogger->log(LogLevel::INFO, 'We have a PSR-compatible logger');

To select a PSR-3 backend for writing, we can use the Zend\Log\Writer\Psr class. In order to use it, you need to pass a Psr\Log\LoggerInterface instance to the $psrLogger constructor argument:

$writer = new Zend\Log\Writer\Psr($psrLogger);

zend-log also supports PSR-3 message placeholders via the Zend\Log\Processor\PsrPlaceholder class. To use it, you need to add a PsrPlaceholder instance to a logger, using the addProcess() method. Placeholder names correspond to keys in the "extra" array passed when logging a message:

use Zend\Log\Logger;
use Zend\Log\Processor\PsrPlaceholder;

$logger = new Logger;
$logger->addProcessor(new PsrPlaceholder);

$logger->info('User with email {email} registered', ['email' => 'user@example.org']);

An informational log entry will be stored with the message User with email user@example.org registered.

Logging an MVC application

If you are using a zend-mvc based application, you can use zend-log as module. zend-log provides a Module.php class, which registers Zend\Log as a module in your application.

In particular, the zend-log module provides the following services (under the namespace Zend\Log):

Logger::class         => LoggerServiceFactory::class,
'LogFilterManager'    => FilterPluginManagerFactory::class,
'LogFormatterManager' => FormatterPluginManagerFactory::class,
'LogProcessorManager' => ProcessorPluginManagerFactory::class,
'LogWriterManager'    => WriterPluginManagerFactory::class,

The Logger::class service can be configured using the log config key; the documentation provides configuration examples.

In order to use the Logger service in your MVC stack, grab it from the service container. For instance, you can pass the Logger service in a controller using a factory:

use Zend\Log\Logger;
use Zend\ServiceManager\Factory\FactoryInterface;

class IndexControllerFactory implements FactoryInterface
{
    public function __invoke(
        ContainerInterface $container,
        $requestedName,
        array $options = null
    ) {
        return new IndexController(
            $container->get(Logger::class)
        );
    }
}

via the following service configuration for the IndexController:

'controllers' => [
    'factories' => [
        IndexController::class => IndexControllerFactory::class,
    ],
],

Logging a middleware application

You can also integrate zend-log in your middleware applications. If you are using Expressive, add the component's ConfigProvider to your config/config.php file.

Note: if you are using zend-component-installer, you will be prompted to install zend-log's config provider when you install the component via Composer.

Note: This configuration registers the same services provided in the zend-mvc example, above.

To use zend-log in middleware, grab it from the dependency injection container and pass it as a dependency to your middleware:

namespace App\Action;

use Psr\Container\ContainerInterface;
use Zend\Log\Logger;

class HomeActionFactory
{
    public function __invoke(ContainerInterface $container) : HomeAction
    {
        return new HomeAction(
            $container->get(Logger::class)
        );
    }
}

As an example of logging in middleware:

namespace App\Action;

use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface as ServerMiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Log\Logger;

class HomeAction implements ServerMiddlewareInterface
{
    private $logger;

    public function __construct(Logger $logger)
    {
        $this->logger = logger;
    }

    public function process(
        ServerRequestInterface $request,
        DelegateInterface $delegate
    ) {
        $this->logger->info(__CLASS__ . ' has been executed');

        // ...
    }
}

Listening for errors in Expressive

Expressive and Stratigility provide a default error handler middleware implementation, Zend\Stratigility\Middleware\ErrorHandler which listens for PHP errors and exceptions/throwables. By default, it spits out a simple error page when an error occurs, but it also provides the ability to attach listeners, which can then act on the provided error.

Listeners receive the error, the request, and the response that the error handler will be returning. We can use that information to log information!

First, we create an error handler listener that composes a logger, and logs the information:

use Exception;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;
use Zend\Log\Logger;

class LoggingErrorListener
{
    /**      
     * Log message string with placeholders
     */
    const LOG_STRING = '{status} [{method}] {uri}: {error}';

    private $logger;

    public function __construct(Logger $logger)
    {
        $this->logger = $logger;
    }

    public function __invoke(
        $error,
        ServerRequestInterface $request,
        ResponseInterface $response
    ) {
        $this->logger->error(self::LOG_STRING, [
            'status' => $response->getStatusCode(),
            'method' => $request->getMethod(),
            'uri'    => (string) $request->getUri(),
            'error'  => $error->getMessage(),
        ]);
    }
}

The ErrorHandler implementation casts PHP errors to ErrorException instances, which means that $error is always some form of throwable.

We can then write a delegator factory that will register this as a listener on the ErrorHandler:

use LoggingErrorListener;
use Psr\Container\ContainerInterface;
use Zend\Log\Logger;
use Zend\Log\Processor\PsrPlaceholder;
use Zend\Stratigility\Middleware\ErrorHandler;

class LoggingErrorListenerFactory
{
    public function __invoke(
        ContainerInterface $container,
        $serviceName,
        callable $callback
    ) : ErrorHandler {
        $logger = $container->get(Logger::class);
        $logger->addProcessor(new PsrPlaceholder());

        $listener = new LoggingErrorListener($logger);
        
        $errorHandler = $callback();
        $errorHandler->attachListener($listener);
        return $errorHandler;
    }
}

And then register the delegator in your configuration:

// In a ConfigProvider, or a config/autoload/*.global.php file:
use LoggingErrorListenerFactory;
use Zend\Stratigility\Middleware\ErrorHandler;

return [
    'dependencies' => [
        'delegators' => [
            ErrorHandler::class => [
                LoggingErrorListenerFactory::class,
            ],
        ],
    ],
];

At this point, your error handler will now also log errors to your configured writers!

Summary

The zend-log component offers a wide set of features, including support for multiple writers, filtering of log data, compatibility with PSR-3, and more.

Hopefully you can use the examples above for consuming zend-log in your standalone, zend-mvc, Expressive, or general middleware applications!

Learn more in the zend-log documentation.

Source

When writing PSR-7 middleware, at some point you'll need to return a response.

Maybe you'll be returning an empty response, indicating something along the lines of successful deletion of a resource. Maybe you need to return some HTML, or JSON, or just plain text. Maybe you need to indicate a redirect.

But here's the problem: a generic response typically has a very generic constructor. Take, for example, Zend\Diactoros\Response:

public function __construct(
    $body = 'php://memory',
    $status = 200,
    array $headers = []
)

$body in this signature allows either a Psr\Http\Message\StreamInterface instance, a PHP resource, or a string identifying a PHP stream. This means that it's not terribly easy to create even a simple HTML response!

To be fair, there are good reasons for a generic constructor: it allows setting the initial state in such a way that you'll have a fully populated instance immediately. However, the means for doing so, in order to be generic, leads to convoluted code for most consumers.

Fortunately, Diactoros provides a number of convenience implementations to help simplify the most common use cases.

EmptyResponse

The standard response from an API for a successful deletion is generally a 204 No Content. Sites emitting webhook payloads often expect a 202 Accepted with no content. Many APIs that allow creation of resources will return a 201 Created; these may or may not have content, depending on implementation, with some being empty, but returning a Location header with the URI of the newly created resource.

Clearly, in such cases, if you don't need content, why would you be bothered to create a stream? To answer this, we have Zend\Diactoros\Response\EmptyResponse, with the following constructor:

public function __construct($status = 204, array $headers = [])

So, a DELETE endpoint might return this on success:

return new EmptyResponse();

A webhook endpoint might do this:

return new EmptyResponse(StatusCodeInterface::STATUS_ACCEPTED);

An API that just created a resource might do the following:

return new EmptyResponse(
    StatusCodeInterface::STATUS_CREATED,
    ['Location' => $resourceUri]
);

RedirectResponse

Redirects are common within web applications. We may want to redirect a user to a login page if they are not currently logged in; we may have changed where some of our content is located, and redirect users requesting the old URIs; etc.

Zend\Diactoros\Response\RedirectResponse provides a simple way to create and return a response indicating an HTTP redirect. The signature is:

public function __construct($uri, $status = 302, array $headers = [])

where $uri may be either a string URI, or a Psr\Http\Message\UriInterface instance. This value will then be used to seed a Location HTTP header.

return new RedirectResponse('/login');

You'll note that the $status defaults to 302. If you want to set a permanent redirect, pass 301 for that argument:

return new RedirectResponse('/archives', 301);

// or, using fig/http-message-util:
return new RedirectResponse('/archives', StatusCodeInterface::STATUS_PERMANENT_REDIRECT);

Sometimes you may want to set an header as well; do that by passing the third argument, an array of headers to provide:

return new RedirectResponse(
    '/login',
    StatusCodeInterface::STATUS_TEMPORARY_REDIRECT,
    ['X-ORIGINAL_URI' =>  $uri->getPath()]
);

TextResponse

Sometimes you just want to return some text, whether it's plain text, XML, YAML, etc. When doing that, taking the extra step to create a stream feels like overhead:

$stream = new Stream('php://temp', 'wb+');
$stream->write($content);

To simplify this, we offer Zend\Diactoros\Response\TextResponse, with the following signature:

public function __construct($text, $status = 200, array $headers = [])

By default, it will use a Content-Type of text/plain, which means you'll often need to supply a Content-Type header with this response.

Let's return some plain text:

return new TextResponse('Hello, world!');

Now, let's try returning a Problem Details XML response:

return new TextResponse(
    $xmlPayload,
    StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY,
    ['Content-Type' => 'application/problem+xml']
);

If you have some textual content, this is the response for you.

HtmlResponse

The most common response from web applications is HTML. If you're returning HTML, even the TextResponse may seem a bit much, as you're forced to provide the Content-Type header. To answer that, we provide Zend\Diactoros\Response\HtmlResponse, which is exactly the same as TextResponse, but with a default Content-Type header specifying text/html; charset=utf-8 instead.

As an example:

return new HtmlResponse($renderer->render($template, $view));

JsonResponse

For web APIs, JSON is generally the lingua franca. Within PHP, this generally means passing an array or object to json_encode(), and supplying a Content-Type header of application/json or application/{type}+json, where {type} is a more specific mediatype.

Like text and HTML, you likely don't want to do this manually every time:

$json = json_encode(
  $data,
  JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES
);
$stream = new Stream('php://temp', 'wb+');
$stream->write($json);
$response = new Response(
    $stream,
    StatusCodeInterface::STATUS_OK,
    ['Content-Type' => 'application/json']
);

To simplify this, we provide Zend\Diactoros\Response\JsonResponse, with the following constructor signature:

public function __construct(
    $data,
    $status = 200,
    array $headers = [],
    $encodingOptions = self::DEFAULT_JSON_FLAGS
) {

where $encodingOptions defaults to the flags specified in the previous example.

This means our most common use case now becomes this:

return new JsonResponse($data);

What if we want to return a JSON-formatted Problem Details response?

return new JsonResponse(
    $details,
    StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY,
    ['Content-Type' => 'application/problem+json']
);

One common workflow we've seen with JSON responses is that developers often want to manipulate them on the way out through middleware. As an example, they may want to add additional _links elements to HAL responses, or add counts for collections.

Starting in version 1.5.0, we provide a few extra methods on this particular response type:

public function getPayload() : mixed;
public function getEncodingOptions() : int;
public function withPayload(mixed $data) : JsonResponse;
public function withEncodingOptions(int $options) : JsonResponse;

Essentially, what happens is we now store not only the encoded $data internally, but the raw data; this allows you to pull it, manipulate it, and then create a new instance with the updated data. Additionally, we allow specifying a different set of encoding options later; this can be useful, for instance, for adding the JSON_PRETTY_PRINT flag when in development. When the options are changed, the new instance will also re-encode the existing data.

First, let's look at altering the payload on the way out. zend-expressive-hal injects _total_items, _page, and _page_count properties, and you may want to remove the underscore prefix for each of these:

function (ServerRequestInterface $request, DelegateInterface $delegate) : ResponseInterface
{
    $response = $delegate->process($request);
    if (! $response instanceof JsonResponse) {
        return $response;
    }

    $payload = $response->getPayload();
    if (! isset($payload['_total_items'])) {
        return $response;
    }

    $payload['total_items'] = $payload['_total_items'];
    unset($payload['_total_items']);

    if (isset($payload['_page'])) {
        $payload['page'] = $payload['_page'];
        $payload['page_count'] = $payload['_page_count'];
        unset($payload['_page'], $payload['_page_count']);
    }

    return $response->withPayload($payload);
}

Now, let's write middleware that sets the JSON_PRETTY_PRINT option when in development mode:

function (
    ServerRequestInterface $request,
    DelegateInterface $delegate
) : ResponseInterface use ($isDevelopmentMode) {
    $response = $delegate->process($request);

    if (! $isDevelopmentMode || ! $response instanceof JsonResponse) {
        return $response;
    }

    $options = $response->getEncodingOptions();
    return $response->withEncodingOptions($options | JSON_PRETTY_PRINT);
}

These features can be really powerful when shaping your API!

Summary

The goal of PSR-7 is to provide the ability to standardize on interfaces for your HTTP interactions. However, at some point you need to choose an actual implementation, and your choice will often be shaped by the features offered, particularly if they provide convenience in your development process. Our goal with these various custom response implementations is to provide convenience to developers, allowing them to focus on what they need to return, not how to return it.

You can check out more in the Diactoros documentation.

Source

PHP 7.2 will be released later this year (2017). This version contains some interesting additions, including two new security features: support of the Argon2 password hash algorithm, and the ext/sodium extension wrapping the libsodium library.

With these new features, PHP is the first programming language to adopt modern cryptography in its standard library.

In this article, we demonstrate the usage of the Argon2 password hash algorithm.

Installation of PHP 7.2

If you are reading this article before the general availability of 7.2, you need to compile PHP to use that version. You can download the source code from the PHP downloads site. Today, 17 August 2017, the most recent available version is 7.2.0 Beta 3 (file php-7.2.0beta3.tar.gz).

Before compiling PHP, you need to install the argon2 library. If you are using a Debian/Ubuntu Linux distribution, you can run the following command:

sudo apt install argon2 libargon2-0 libargon2-0-dev

To compile PHP, you need to extract the previous source code in a folder and run the following commands:

./configure --with-password-argon2
make
make install

Please note the usage of the option --with-password-argon2 for including support for the Argon2 algorithm.

This will install PHP 7.2 as the default PHP on your system. If you do not want to change the default PHP, you can omit the execution of the last command make install, or use the --prefix option to configure to specify an alternate location. In each of these cases, you will need to reference PHP 7.2 using the path of the folder installation.

Argon2

Argon2 is a password-based key derivation function winner of the Password Hashing Competition in July 2015.

This function is an evolution of the bcrypt and scrypt algorithms.

Argon2 provides security against brute force attacks using a predefined memory size, CPU time, and a degree of parallelism to prevent GPU attacks.

It uses 3 parameters that control the memory requirements, the execution time, and the parallelism level.

There are two main versions of this algorithm: Argon2i and Argon2d. Argon2i is the safest against side-channel attacks, while Argon2d provides the highest resistance against GPU cracking attacks.

Argon2d is not suitable for password hashing and should not be used.

PHP 7.2 adds Argon2i support to its Password Hashing Functions.

Usage of Argon2i in PHP

Argon2 support in PHP was proposed by Charles R. Portwood II in via an RFC.

The implemented algorithm in PHP is Argon2i (v1.3), and it can be provided via the $algo parameter to the password_hash() function. The signature of password_hash() is as follows:

password_hash( string $password , integer $algo [, array $options ]) : string

The second parameter ($algo) specifies the algorithm to use when hashing; the Argon2i algorithm is represented by the constant PASSWORD_ARGON2I.

As an example:

$password = 'test';
$hash = password_hash($password, PASSWORD_ARGON2I);
var_dump($hash);

The $hash result will contains a string of 98 characters as follows:

$argon2i$v=19$m=1024,t=2,p=2$TmxLemFoVnZFaEJuT1NyYg$4j2ZFDn1fVS70ZExmlJ33rXOinafcBXrp6A6grHEPkI

This string contains sub-string of parts, separated by dollar ($). These parts are:

argon2i
v=19
m=1024,t=2,p=2
TmxLemFoVnZFaEJuT1NyYg
4j2ZFDn1fVS70ZExmlJ33rXOinafcBXrp6A6grHEPkI

The first part is the algorithm name (argon2i), the second is the Argon2i version, and the third part is a list of algorithm parameters related to memory cost (in Kb), time cost, and threads to be used (parallelism).

The fourth parameter is the random salt value, encoded in Base64. This value is generated by password_hash() using a random value for each execution. This is why we have different hash outputs for the same input string. The default size of the salt is 16 bytes.

The fifth and last parameter of the string contains the hash value, encoded in Base64. The hash size is 32 bytes.

PHP provides a function named password_get_info($hash) to get information about the hash generated by password_hash(). For instance, if you use password_get_info() on the previous value, you will receive:

array(3) {
  ["algo"]=>
  int(2)
  ["algoName"]=>
  string(7) "argon2i"
  ["options"]=>
  array(3) {
    ["memory_cost"]=>
    int(1024)
    ["time_cost"]=>
    int(2)
    ["threads"]=>
    int(2)
  }
}

The default parameters for the algorithm are a memory_cost of 1024 Kb (1 Mb), a time_cost of 2, and two threads to be used for parallelism. The Argon2 specifications suggest to use a power of 2 value for the memory_cost.

These values can be changed using the $options parameter of the password_hash() function. As an example:

$password = 'test';
$options = [
    'memory_cost' => 1<<17, // 128 Mb
    'time_cost'   => 4,
    'threads'     => 3,
];
$hash = password_hash($password, PASSWORD_ARGON2I, $options);
var_dump($hash);

PHP will generate an E_WARNING for values that cannot be used as options for the PASSWORD_ARGON2I algorithm.

Regarding the default option values, we suggest to change it according to the use cases and CPU + RAM available. From the PHP RFC:

Due to the variety of platforms PHP runs on, the cost factors are deliberately set low as to not accidentally exhaust system resources on shared or low resource systems when using the default cost parameters. Consequently, users should adjust the cost factors to match the system they're working on. As Argon2 doesn't have any "bad" values, however consuming more resources is considered better than consuming less. Users are encouraged to adjust the cost factors for the platform they're developing for.

Conclusion

In this article we demonstrated usager of the Argon2 password hash algorithm with PHP 7.2. The Argon2 algorithm is the state of the art for password protection and it can be now used in PHP without installing additional extensions. This is a very nice security feature that will improve the security of PHP applications that store user passwords. In a future article, we will cover the Sodium extension, another new security feature included in PHP 7.2. With these new features, PHP is the first language to support modern cryptography in the core of the language.

Source

We've been working towards our various Apigility on Expressive goals, and have recently published two new components:

These components provide response representations for APIs built with PSR-7 middleware. Specifically, they provide:

These two formats provide both JSON and XML representation options (the latter through a secondary proposal).

What's in a representation?

So you're developing an API!

What can clients expect when they make a request to your API? Will they get a wall of text? or some sort of serialization? If it's a serialized format, which ones do you support? And how is the data structured?

The typical answer will be, "we'll provide JSON responses." That answers the serialization aspect, but not the data structure; for that, you might develop and publish a schema for your end users, so they know how to parse the response.

But there may still be unanswered questions when you do so:

  • How does the consumer know what actions can next be taken, or what resources might be related to the one requested?
  • If the resource contains other entities, how can they identify which ones they can request separately, versus those that are just part of the data structure?

These and all of the previous are questions that a representation format answers. A well-considered representation format will:

  • Provide links to the actions that may be performed next, as well as to related resources.
  • Indicate which data elements represent other requestable resources.
  • Be extensible, to allow representing arbitrary data.

I tend to think of representations as falling into two buckets:

  • Representations of errors.
  • Representations of application resources.

Errors need separate representation, as they are not requestable on their own; they are returned when something goes wrong, and need to provide enough detail that the consumer can determine what they need to change in order to perform a new request.

The Problem Details specification provides exactly this. As an example:

{
    "type": "https://example.com/problems/rate-limit-exceeded",
    "title": "You have exceeded your API rate limit.",
    "detail": "You have hit your rate limit of 5000 requests per hour.",
    "requests_this_hour": 5025,
    "rate_limit": 5000,
    "rate_limit_reset": "2017-05-03T14:39-0500"
}

We chose Problem Details to standardize on when starting the Apigility project as it has very few requirements, but can model any error easily. The ability to link to documentation detailing general error types provides the ability to communicate with your consumers about known errors and how to correct them.

Application resources generally should have their own schema, but having a predictable structure for providing relational links (answering the "what can I do next" question) and embedding related resources can help those making clients or those consuming your API to automate many of their processes. Instead of having a list of URLs they can access, they can hit one resource, and start following the composed links; when they present data, they can also present controls for the embedded resources, making it simpler to make requests to these other items.

HAL provides these details in a simple way: relational links are objects under the _links element, and embedded resources are under the _embedded element; all other data is represented as normal key/value pairs, allowing for arbitrary nesting of structures. An example payload might look like the following:

{
    "_links": {
        "self": { "href": "/api/books?page=7" },
        "first": { "href": "/api/books?page=1" },
        "prev": { "href": "/api/books?page=6" },
        "next": { "href": "/api/books?page=8" },
        "last": { "href": "/api/books?page=17" }
        "search": {
            "href": "/api/books?query={searchTerms}",
            "templated": true
        }
    },
    "_embedded": {
        "book": [
            {
                "_links": {
                    "self": { "href": "/api/books/1234" }
                }
                "id": 1234,
                "title": "Hitchhiker's Guide to the Galaxy",
                "author": "Adams, Douglas"
            },
            {
                "_links": {
                    "self": { "href": "/api/books/6789" }
                }
                "id": 6789,
                "title": "Ancillary Justice",
                "author": "Leckie, Ann"
            }
        ]
    },
    "_page": 7,
    "_per_page": 2,
    "_total": 33
}

The above provides controls to allow a consumer to navigate through a result set, as well as to perform another search against the API. It provides data about the result set, and also embeds a number of resources, with links so that the consumer can make requests against those individually. Having links present in the payloads means that if the URI scheme changes later, a well-written client will be unaffected, as it will follow the links delivered in response payloads instead of hard-coding them. This allows our API to evolve, without affecting the robustness of clients.

A number of other representation formats have become popular over the years, including:

Each are powerful and flexible in their own right. We standardized on HAL for Apigility originally as it was one of the first published specifications; we've continued with it as it is a format that's both easy to generate as well as parse, and extensible enough to answer the needs of most API representations.

zend-problem-details

The package zendframework/zend-problem-details provides a Problem Details implementation for PHP, and specifically for generating PSR-7 responses. It provides a multi-faceted approach to providing error details to your users.

First, you can compose the ProblemDetailsResponseFactory into your middleware, and use it to generate and return your error responses:

return $this->problemDetails->createResponse(
    $request,                                           // PSR-7 request
    422,                                                // HTTP status
    'Invalid data detected in book submission',         // Detail
    'Invalid book',                                     // Problem title
    'https://example.com/api/doc/errors/invalid-book',  // Problem type (URL to details)
    ['messages' => $validator->getMessages()]           // Additional data
);

The request instance is passed to the factory to allow it to perform content negotiation; zend-problem-details uses the Accept header to determine whether to serve a JSON or an XML representation, defaulting to XML if it is unable to match to either format.

The above will generate a response like the following:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json

{
  "status": 422,
  "title": "Invalid Book",
  "type": "https://example.com/api/doc/errors/invalid-book",
  "detail": "Invalid data detected in book submission",
  "messages": [
    "Missing title",
    "Missing author"
  ]
}

ProblemDetailsFactory is agnostic of PSR-7 implementation, and allows you to inject a response prototype and stream factory during instantiation. By default, it uses zend-diactoros for these artifacts if none are provided.

Second, you can create a response from a caught exception or throwable:

return $this->problemDetails->createResponseFromThrowable(
    $request,
    $throwable
);

Currently, the factory uses the exception message for the detail, and 4XX and 5XX exception codes for the status (defaulting to 500 for any other value).

We are currently evaluating a proposal that would have caught exceptions generate a canned Problem Details response with a status of 500, so the above behavior may change in the future. If you want to guarantee the code and message are used, you can create custom exceptions, as outlined below.

Third, extending on the ability to create details from throwables, we provide a custom exception interface, ProblemDetailsException. This interface defines methods for pulling additional information to provide to a Problem Details response:

namespace Zend\ProblemDetails\Exception;

interface ProblemDetailsException
{
    public function getStatus() : int;
    public function getType() : string;
    public function getTitle() : string;
    public function getDetail() : string;
    public function getAdditionalData() : array;
}

If you throw an exception that implements this interface, the createResponseFromThrowable() method shown above will pull data from these methods in order to create the response. This allows you to define domain-specific exceptions that can provide additional details when used in an API context.

Finally, we also provide optional middleware, ProblemDetailsMiddleware, that does the following:

  • Registers an error handler that casts PHP errors in the current error_reporting bitmask to ErrorException instances.
  • Wraps calls to the delegate in a try/catch block.
  • Passes any caught throwables to the createResponseFromThrowable() factory in order to return Problem Details responses.

We recommend using custom exceptions and this middleware, as the combination allows you to focus your efforts on the positive outcome paths within your middleware.

Using it in Expressive

When using Expressive, you can then compose the ProblemDetailsMiddleware within route-specific pipelines, allowing you to have separate error handlers for the API parts of your application:

// In config/routes.php:

// Per route:
$app->get('/api/books', [
    Zend\ProblemDetails\ProblemDetailsMiddleware::class,
    Books\Action\ListBooksAction::class,
], 'books');
$app->post('/api/books', [
    Zend\ProblemDetails\ProblemDetailsMiddleware::class,
    Books\Action\CreateBookAction::class,
]);

Alternately, if all API endpoints have a common URI path prefix, register it as path-segregated middleware:

// In config/pipeline.php:

$app->pipe('/api', Zend\ProblemDetails\ProblemDetailsMiddleware::class);

These approaches allow you to deliver consistently structured, useful errors to your API consumers.

zend-expressive-hal

The package zendframework/zend-expressive-hal provides a HAL implementation for PSR-7 applications. Currently, it allows creating PSR-7 response payloads only; we may consider parsing HAL requests at a future date, however.

zend-expressive-hal implements PSR-13 (Link Definition Interfaces), and provides structures for:

  • Defining relational links
  • Defining HAL resources
  • Composing relational links in HAL resources
  • Embedding HAL resources in other HAL resources

These utilities can be used manually, without any other requirements:

use Zend\Expressive\Hal\HalResource;
use Zend\Expressive\Hal\Link;

$author = new HalResource($authorDataArray);
$author = $author->withLink(
    new Link('self', '/authors/' .  $authorDataArray['id'])
);

$book = new HalResource($bookDataArray);
$book = $book->withLink(
    new Link('self', '/books/' .  $bookDataArray['id'])
);
$book = $book->embed('authors', [$author]);

Both Link and HalResource are immutable; as such, if you wish to make iterative changes, you will need to re-assign the original value.

These clases allow you to model the data to return in your representation, but what about returning a response based on them? To handle that, we have the HalResponseFactory, which will generate a response from a resource provided to it:

return $halResponseFactory->createResponse($request, $book);

Like the ProblemDetailsFactory, the HalResponseFactory is agnostic of PSR-7 implementation, and allows you to inject a response prototype and stream factory during instantiation.

Also, it, too, uses content negotiation in order to determine whether a JSON or XML response should be generated.

The above might generate the following response:

HTTP/1.1 200 OK
Content-Type: application/hal+json

{
  "_links": {
    "self": {"href": "/books/42"}
  },
  "id": 42
  "title": "The HitchHiker's Guide to the Galaxy",
  "_embedded": {
    "authors": [
      {
        "_links": {
          "self": {"href": "/author/12"}
        },
        "id": 12,
        "name": "Douglas Adams"
      }
    ]
  }
}

If your resources might be used in multiple API endpoints, you may find that creating them manually everywhere you need them is a bit of a chore!

One of the most powerful pieces of zend-expressive-hal is that it provides tools for mapping object types to how they should be represented. This is done via a metadata map, which maps class types to zend-hydrator extractors for the purpose of generating a representation. Additionally, we provide tools for generating link URIs based on defined routes, which allows metadata to provide dynamic link generation for generated resources.

I won't go into the architecture of how all this works, as there's a fair amount of detail. In practice, what will generally happen is:

  • You'll define a metadata map in your application configuration, mapping your own classes to details on how to represent them.
  • You'll compose a Zend\Expressive\Hal\ResourceGenerator (which will use a metadata map based on your configuration) and a HalResponseFactory in your middleware.
  • You'll pass an object to the ResourceGenerator in order to produce a HalResource.
  • You'll pass the generated HalResource to your HalResponseFactory to produce a response.

So, as an example, I might define the following metadata map configuration:

namespace Books;

use Zend\Expressive\Hal\Metadata\MetadataMap;
use Zend\Expressive\Hal\Metadata\RouteBasedCollectionMetadata;
use Zend\Expressive\Hal\Metadata\RouteBasedResourceMetadata;
use Zend\Hydreator\ObjectProperty as ObjectPropertyHydrator;

class ConfigProvider
{
    public function __invoke() : array
    {
        return [
            'dependencies' => $this->getDependencies(),
            MetadataMap::class => $this->getMetadataMap(),
        ];
    }

    public function getDependencies() : array
    {
        return [ /* ... */ ];
    }

    public function getMetadataMap() : array
    {
        return [
            [
                '__class__' => RouteBasedResourceMetadata::class,
                'resource_class' => Author::class,
                'route' => 'author',
                'extractor' => ObjectPropertyHydrator::class,
            ],
            [
                '__class__' => RouteBasedCollectionMetadata::class,
                'collection_class' => AuthorCollection::class,
                'collection_relation' => 'authors',
                'route' => 'authors',
            ],
            [
                '__class__' => RouteBasedResourceMetadata::class,
                'resource_class' => Book::class,
                'route' => 'book',
                'extractor' => ObjectPropertyHydrator::class,
            ],
            [
                '__class__' => RouteBasedCollectionMetadata::class,
                'collection_class' => BookCollection::class,
                'collection_relation' => 'books',
                'route' => 'books',
            ],
        ];
    }
}

The above defines metadata for authors and books, both as individual resources as well as collections. This allows us to then embed an author as a property of a book, and have it represented as an embedded resource!

From there, we could have middleware that composes both a ResourceGenerator and a HalResponseFactory in order to produce representations:

namespace Books\Action;

use Books\Repository;
use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Expressive\Hal\HalResponseFactory;
use Zend\Expressive\Hal\ResourceGenerator;

class ListBooksAction implements MiddlewareInterface
{
    private $repository;
    private $resourceGenerator;
    private $responseFactory;

    public function __construct(
        Repository $repository,
        ResourceGenerator $resourceGenerator,
        HalResponseFactory $responseFactory
    ) {
        $this->repository = $repository;
        $this->resourceGenerator = $resourceGenerator;
        $this->responseFactory = $responseFactory;
    }

    public function process(
        ServerRequestInterface $request,
        DelegateInterface $delegate
    ) : ResponseInterface {
        /** @var \Books\BookCollection $books */
        $books = $this->repository->fetchAll();

        return $this->responseFactory->createResponse(
            $request,
            $this->resourceGenerator->fromObject($books)
        );
    }
}

When using zend-expressive-hal to generate your responses, the majority of your middleware will look almost exactly like this!

We provide a number of other features in the package as well:

  • You can define your own metadata types, and strategy classes for producing representations based on objects matching that metadata.
  • You can specify custom mediatypes for your generated responses.
  • You can provide your own link generation (useful if you're not using Expressive).
  • You can provide your own JSON and XML renderers, if you want to vary the output for some reason (e.g., always adding specific links).

Use Anywhere!

These two packages, while part of the Zend Framework and Expressive ecosystems, can be used anywhere you use PSR-7 middleware. The Problem Details component provides a factory for producing a PSR-7 Problem Details response, and optionally middleware for automating reporting of errors. The HAL component provides only a factory for producing a PSR-7 HAL response, and a number of tools for modeling the data to return in that response.

As such, we encourage Slim, Lumen, and other PSR-7 framework users to consider using these components in your API applications to provide standard, robust, and extensible representations to your users!

For more details and examples, visit the docs for each component:

Source

We've been working on the Apigility on Expressive initiative for a couple months now, and have a bit of progress to report.

First, if you're unfamiliar with the initiative, please head over and read the RFC.

In this post, we'll discuss what's done and ready to review, and what pieces are in the works.

Ready to review

Two pieces are currently ready to review:

These two provide us the representations that will be returned by your API. Problem Details is used to describe API errors — whether those are due to the client sending bad information, or server-side errors that occur. HAL is used to provide your API payloads to the client.

Problem Details

There are three facets to the proposed implementation:

  • We provide a ProblemDetailsResponseFactory for you to compose in middleware. When you encounter an error condition, you can use it to generate and return a Problem Details response. It has built-in content negotiation, and will return either a JSON or XML response based on the Accept client request header.

  • We provide a custom exception interface, ProblemDetailsException, which you can implement that defines a number of getter methods for retrieving information to use when building a Problem Details response. (We also provide a trait, CommonProblemDetailsException, that implements the various getters, allowing you to focus on constructors.)

  • We provide ProblemDetailsMiddleware, which acts as error handling middleware, catching exceptions and PHP errors and turning them into Problem Details responses via the ProblemDetailsResponseFactory. If you throw a ProblemDetailsException, this middleware will pull data from it to fully populate the error details!

We feel these three faculties allow a great deal of flexibility in how you handle errors for your APIs.

HAL

Our HAL implementation has several facets:

  • Low-level value objects representing relational links and HAL resources. These can be created manually, and independently of any other ZF components.

  • A LinkGenerator that uses a PSR-7 request instance and a composed UrlGenerator to allow creating links that reference application routes.

  • Renderers for both JSON and XML. Each accepts a HAL resource, with its relational links, and produces the serialized version.

  • A ResourceGenerator that maps an object to related metadata, and the related metadata to a strategy for creating the HAL resource. The shipped metadata and strategies use zend-hydrator for extracting data from objects, and zend-paginator awareness for producing pagination relational links.

  • A HalResponseFactory for rendering resources and returning PSR-7 responses. It has built-in content negotiation to allow producing a response with the correct format.

While the library allows developers to manually create resources and links, the real power comes from the ability to pass objects directly to the ResourceGenerator in order to create a fully populated HAL resource with its self-relational link; this vastly reduces boilerplate in middleware.

Examples

The following demonstrates how you might use the two features together within middleware to return responses.

First, we have some configuration for the metadata map that tells it how we want to represent our objects:

// In Books\ConfigProvider, or a config/autoload/*.global.php file:

use Books\Book;
use Books\BookCollection;
use Hal\Metadata\MetadataMap;
use Hal\Metadata\RouteBasedCollectionMetadata;
use Hal\Metadata\RouteBasedResourceMetadata;
use Zend\Hydrator\ObjectProperty as ObjectPropertyHydrator;

MetadataMap::class => [
    [
          [
              '__class__' => RouteBasedResourceMetadata::class,
              'resource_class' => Book::class,
              'route' => 'book',
              'extractor' => ObjectPropertyHydrator::class,
          ],
          [
              '__class__' => RouteBasedCollectionMetadata::class,
              'collection_class' => BookCollection::class,
              'collection_relation' => 'book',
              'route' => 'books',
          ],
    ],
],

Books\Book is a value object with public properties. Books\BookCollection extends Zend\Paginator\Paginator, allowing a paginated collection.

We will also assume we have the following routes defined:

  • book will map to /books/{id}
  • books will map to /books

Finally, we get to our middleware. It assumes a Books\Repository, which is simply a class that accesses our persistent storage.

namespace Books;

use Hal\HalResponseFactory;
use Hal\ResourceGenerator;
use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface;
use ProblemDetails\ProblemDetailsResponseFactory;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Expressive\Helper\ServerUrlHelper;
use Zend\Expressive\Helper\UrlHelper;

class BookMiddleware implements MiddlewareInterface
{
    /** @var ProblemDetailsResponseFactory */
    private $problemDetails;

    /** @var Repository */
    private $repository;

    /** @var ResourceGenerator */
    private $resourceGenerator;

    /** @var HalResponseFactory **/
    private $responseFactory;

    public function __construct(
        Repository $repository,
        ResourceGenerator $resourceGenerator,
        HalResponseFactory $responseFactory,
        ProblemDetailsResponseFactory $problemDetails
    ) {
        $this->repository = $repository;
        $this->resourceGenerator = $resourceGenerator;
        $this->responseFactory = $responseFactory;
        $this->problemDetails = $problemDetails;
    }

    /**
     * @param ServerRequestInterface $request
     * @param DelegateInterface $delegate
     * @return ResponseInterface
     */
    public function process(ServerRequestInterface $request, DelegateInterface $delegate)
    {
        $id = $request->getAttribute('id', false);

        if (false === $id) {
            // Return a problem details response!
            return $this->problemDetails->createResponse(
                $request,
                400,
                'Missing book identifier',
                'Client Error',
                'book.id'
            );
        }

        $user = $request->getAttribute('user');

        try {
            $book = $this->repository->fetch($id, $user);
        } catch (Exception\BookNotFoundException $e) {
            // Return a problem details response!
            return $this->problemDetails->createResponse(
                $request,
                404,
                'Book not found',
                'Not Found',
                'book.not_found',
                [ 'book_id' => $id]
            );
        }

        // Create the resource
        $resource = $this->resourceGenerator->fromObject($book, $request);

        // Add another relational link
        $resource->withLink($this->resourceGenerator->getLinkGenerator()->templatedFromRoute(
            'search',
            $request,
            'books',
            [],
            ['query' => '{searchTerms}']
        ));

        // Return a response with the accepted representation
        return $this->responseFactory->createResponse($request, $resource);
    }
}

A different approach we could take would be to have our exceptions implement ProblemDetailsException, and either throw them directly, or simply not catch them. We would then register the ProblemDetailsMiddleware within our routed middleware:

$app->get('/books/{id}', [
    \ProblemDetails\ProblemDetailsMiddleware::class,
    \Books\BookMiddleware::class,
], 'book');

The approaches allow our middleware to focus primarily on gathering input, calling our model, and then preparing a response.

In the works

While these two are ready to review, we also have a number of other modules in the works, and likely ready to review in the next few weeks:

  • Authentication (by Enrico Zimuel)
  • Authorization (by Enrico Zimuel)
  • OAuth2 (by Julien Guittard)

The content negotiation module scope has decreased; since the proposed Problem Details and HAL modules have negotiation built-in, we only need to focus on the problem of negotiating incoming data. As such, we can likely tackle this quickly as well.

Help out!

We'd love for you to help out. You can do so by reviewing the linked RFCs, as well as trying out the current code in your projects and reporting issues or proposing improvements.

We're excited to start building full-fledged, featureful REST APIs with Expressive!

Source

APIs are all the rage these days, and a tremendous number of them are being written in PHP. When APIs were first gaining popularity, this seemed like a match made in heaven: query the database, pass the results to json_encode(), and voilà! API payload! In reverse, it's json_decode(), pass the data to the database, and done!

Modern day professional PHP, however, is skewing towards usage of value objects and entities, but we're still creating APIs. How can we take these objects and create our API response payloads? How can we take incoming data and transform it into the domain objects we need?

Zend Framework's answer to that question is zend-hydrator. Hydrators can extract an associative array of data from an object, and hydrate an object from an associative array of data.

Installation

As with our other components, you can install zend-hydrator by itself:

$ composer require zendframework/zend-hydrator

Out-of-the-box, it only requires zend-stdlib, which is used internally for transforming iterators to associative arrays. However, there are a number of other interesting, if optional, features that require other components:

  • You can create an aggregate hydrator where each hydrator is responsible for a subset of data. This requires zend-eventmanager.
  • You can filter/normalize the keys/properties of data using naming strategies; these require zend-filter.
  • You can map object types to hydrators, and delegate hydration of arbitrary objects using the DelegatingHydrator. This feature utilizes the provided HydratorPluginManager, which requires zend-servicemanager.

In our examples below, we'll be demonstrating naming strategies and the delegating hydrator, so we will install the dependencies those need:

$ composer require zendframework/zend-filter zendframework/zend-servicemanager

Objects to arrays and back again

Let's take the following class definition:

namespace Acme;

class Book
{
    private $id;

    private $title;

    private $author;

    public function __construct(int $id, string $title, string $author)
    {
        $this->id = $id;
        $this->title = $title;
        $this->author = $author;
    }
}

What we have is a value object, with no way to publicly grab any given datum. We now want to represent it in our API. How do we do that?

The answer is via reflection, and zend-hydrator provides a solution for that:

use Acme\Book;
use Zend\Hydrator\Reflection as ReflectionHydrator;

$book = new Book(42, 'Hitchhiker\'s Guide to the Galaxy', 'Douglas Adams');

$hydrator = new ReflectionHydrator();
$data = $hydrator->extract($book);

We now have an array representation of our Book instance!

Let's say that somebody has just submitted a book via a web form or an API. We have the values, but want to create a Book out of them.

use Acme\Book;
use ReflectionClass;
use Zend\Hydrator\Reflection as ReflectionHydrator;

$hydrator = new ReflectionHydrator();
$book = $hydrator->hydrate(
    $incomingData,
    (new ReflectionClass(Book::class))->newInstanceWithoutConstructor()
);

And now we have a Book instance!

The newInstanceWithoutConstructor() construct is necessary in this case because our class has required constructor arguments. Another possibility is to provide an already populated instance, and hope that the submitted data will overwrite all data in the class. Alternately, you can create classes that have optional constructor arguments.

Most of the time, it can be as simple as this: create an appropriate hydrator instance, and use either extract() to get an array representation of the object, or hydrate() to create an instance from an array of data.

We provide a number of standard implementations:

  • Zend\Hydrator\ArraySerializable works with ArrayObject implementations. It will also hydrate any object implementing either the method exchangeArray() or populate(), and extract from any object implementing getArrayCopy().
  • Zend\Hydrator\ClassMethods will use setter and getter methods to populate and extract objects. It also understands has*() and is*() methods as getters.
  • Zend\Hydrator\ObjectProperty will use public instance properties.
  • Zend\Hydrator\Reflection can extract and populate instance properties of any visibility.

Filtering values

Since a common rationale for extracting data from objects is to create payloads for APIs, you may find there is data in your object you do not want to represent.

zend-hydrator provides a Zend\Hydrator\Filter\FilterInterface for accomplishing this. Filters implement the following:

namespace Zend\Hydrator\Filter;

interface FilterInterface
{
    /**
     * @param string $property
     * @return bool
    public function filter($property);
}

If a filter returns a boolean true, the value is kept; otherwise, it is omitted.

A FilterComposite implementation allows attaching multiple filters; each property is then checked against each filter. (This class also allows attaching standard PHP callables for filters, instead of FilterInterface implementations.) A FilterEnabledInterface allows a hydrator to indicate it composes filters. Tying it together, all shipped hydrators inherit from a common base that implements FilterEnabledInterface by composing a FilterComposite, which means that you can use filters immediately in a standard fashion.

As an example, let's say we have a User class that has a password property; we clearly do not want to return the password in our payload, even if it is properly hashed! Filters to the rescue!

use Zend\Hydrator\ObjectProperty as ObjectPropertyHydrator;

$hydrator = new ObjectPropertyHydrator();
$hydrator->addFilter('password', function ($property) {
    return $property !== 'password';
});
$data = $hydrator->extract($user);

Some hydrators actually use filters internally in order to do their work. As an example, the ClassMethods hydrator composes the following by default:

  • IsFilter, to identify methods beginning with is, such as isTransaction().
  • HasFilter, to identify methods beginning with has, such as hasAuthor().
  • GetFilter, to identify methods beginning with get, such as getTitle().
  • OptionalParametersFilter, to ensure any given matched method can be executed without requiring any arguments.

This latter point brings up an interesting feature: since hydration runs each potential property name through each filter, you may need to setup rules. For example, with the ClassMethods hydrator, a given method name is valid if the following condition is met:

(matches "is" || matches "has" || matches "get") && matches "optional parameters"

As such, when calling addFilter(), you can specify an optional third argument: a flag indicating whether to OR or AND the given filter (using the values FilterComposite::CONDITION_OR or FilterComposite::FILTER_AND); the default is to OR the new filter.

Filtering is very powerful and flexible. If you remember only two things about filters:

  • They only operate during extraction.
  • They can only be used to determine what values to keep in the extracted data set.

Strategies

What if you wanted to alter the values returned during extraction or hydration? zend-hydrator provides these features via strategies.

A strategy provides functionality both for extracting and hydrating a value, and simply transforms it; think of strategies as normalization filters. Each implements Zend\Hydrator\Strategy\StrategyInterface:

namespace Zend\Hydrator\Strategy;

interface StrategyInterface
{
    public function extract($value;)
    public function hydrate($value;)
}

Like filters, a StrategyEnabledInterface allows a hydrator to indicate it accepts strategies, and the AbstractHydrator implements this interface, allowing you to use strategies out of the box with the shipped hydrators.

Using our previous User example, we could, instead of omitting the password value, instead return a static ******** value; a strategy could allow us to do that. Data submitted would be instead hashed using password_hash():

namespace Acme;

use Zend\Hydrator\Strategy\StrategyInterface;

class PasswordStrategy implements StrategyInterface
{
    public function extract($value)
    {
        return '********';
    }

    public function hydrate($value)
    {
        return password_hash($value);
    }
}

We would then extract our data as follows:

use Acme\PasswordStrategy;
use Zend\Hydrator\ObjectProperty as ObjectPropertyHydrator;

$hydrator = new ObjectPropertyHydrator();
$hydrator->addStrategy('password', new PasswordStrategy());
$data = $hydrator->extract($user);

zend-hydrator ships with a number of really useful strategies for common data:

  • BooleanStrategy will convert booleans into other values (such as 0 and 1, or the strings true and false) and vice versa, according to a map you provide to the constructor.
  • ClosureStrategy allows you to provide callbacks for each of extraction and hydration, allowing you to forego the need to create a custom strategy implementation.
  • DateTimeFormatterStrategy will convert between strings and DateTime instances.
  • ExplodeStrategy is a wrapper around implode and explode(), and expects a delimiter to its constructor.
  • StrategyChain allows you to compose multiple strategies; the return value of each is passed as the value to the next, providing a filter chain.

Filtering property names

We can now filter properties to omit from our representations, as well as filter or normalize the values we ultimately want to represent. What about the property names, though?

In PHP, we often use camelCase to represent properties, but snake_case is typically more accepted for APIs. Additionally, what about when we use getters for our values? We likely don't want to use the actual method name as the property name!

For this reason, zend-hydrator provides naming strategies. These work just like strategies, but instead of working on the value, they work on the property name. Like both filters and strategies, an interface, NamingStrategyEnabledInterface, allows a hydrator to indicate can accept a naming strategy, and the AbstractHydrator implements that interface, to allow out of the box usage of naming strategies on the shipped hydrators.

As an example, let's consider the following class:

namespace Acme;

class Transaction
{
    public $isPublished;
    public $publishedOn;
    public $updatedOn;
}

Let's now extract an instance of that class:

use Acme\Transaction;
use Zend\Hydrator\NamingStrategy\UnderscoreNamingStrategy;
use Zend\Hydrator\ObjectProperty as ObjectPropertyHydrator;

$hydrator = new ObjectPropertyHydrator();
$hydrator->setNamingStrategy(new UnderscoreNamingStrategy());
$data = $hydrator->extract($transaction);

The extracted data will now have the keys is_published, published_on, and updated_on!

This is useful if you know all your properties will be camelCased, but what if you have other needs? For instance, what if you want to rename isPublished to published instead?

A CompositeNamingStrategy class allows you to do exactly that. It accepts an associative array of object property names mapped to the naming strategy to use with it. So, as an example:

use Acme\Transaction;
use Zend\Hydrator\NamingStrategy\CompositeNamingStrategy;
use Zend\Hydrator\NamingStrategy\MapNamingStrategy;
use Zend\Hydrator\NamingStrategy\UnderscoreNamingStrategy;
use Zend\Hydrator\ObjectProperty as ObjectPropertyHydrator;

$underscoreNamingStrategy = new UnderscoreNamingStrategy();
$namingStrategy = new CompositeNamingStrategy([
    'isPublished' => new MapNamingStrategy(['published' => 'isPublished']),
    'publishedOn' => $underscoreNamingStrategy,
    'updatedOn'   => $underscoreNamingStrategy,
]);

$hydrator = new ObjectPropertyHydrator();
$hydrator->setNamingStrategy($namingStrategy);
$data = $hydrator->extract($transaction);

Our data will now have the keys published, published_on, and updated_on!

Unfortunately, if we try and hydrate using our CompositeNamingStrategy, we'll run into issues; the CompositeNamingStrategy does not know how to map the normalized, extracted property names to those the object accepts because it maps a property name to the naming strategy. So, to fix that, we need to add the reverse keys:

$mapNamingStrategy = new MapNamingStrategy(['published' => 'isPublished']);
$underscoreNamingStrategy = new UnderscoreNamingStrategy();
$namingStrategy = new CompositeNamingStrategy([
    // Extraction:
    'isPublished'  => $mapNamingStrategy,
    'publishedOn'  => $underscoreNamingStrategy,
    'updatedOn'    => $underscoreNamingStrategy,

    // Hydration:
    'published'    => $mapNamingStrategy,
    'published_on' => $underscoreNamingStrategy,
    'updated_on'   => $underscoreNamingStrategy,
]);

Delegation

Sometimes we want to compose a single hydrator, but don't know until runtime what objects we'll be extracting or hydrating. A great example of this is when using zend-db's HydratingResultSet, where the hydrator may vary based on the table from which we pull values. Other times, we may want to use the same basic hydrator type, but compose different filters, strategies, or naming strategies based on the object we wish to hydrate or extract.

To accommodate these scenarios, we have two features. The first is Zend\Hydrator\HydratorPluginManager. This is a specialized Zend\ServiceManager\AbstractPluginManager for retrieving different hydrator instances. When used in zend-mvc or Expressive applications, it can be configured via the hydrators configuration key, which uses the semantics for zend-servicemanager, and maps the service to HydratorManager.

As an example, we could have the following configuration:

return [
    'hydrators' => [
        'factories' => [
            'Acme\BookHydrator' => \Acme\BookHydratorFactory::class,
            'Acme\AuthorHydrator' => \Acme\AuthorHydratorFactory::class,
        ],
    ],
];

Manually configuring the HydratorPluginManager

You can also use the HydratorPluginManager programmatically:

$hydrators = new HydratorPluginManager();
$hydrators->setFactory('Acme\BookHydrator', \Acme\BookHydratorFactory::class);
$hydrators->setFactory('Acme\AuthorHydrator', \Acme\AuthorHydratorFactory::class);

The factories might create standard hydrator instances, but configure them differently:

namespace Acme;

use Psr\Container\ContainerInterface;
use Zend\Hydrator\ObjectProperty;
use Zend\Hydrator\NamingStrategy\CompositeNamingStrategy;
use Zend\Hydrator\NamingStrategy\UnderscoreNamingStrategy;
use Zend\Hydrator\Strategy\DateTimeFormatterStrategy;

class BookHydratorFactory
{
    public function __invoke(ContainerInterface $container)
    {
        $hydrator = new ObjectProperty();
        $hydrator->addFilter('isbn', function ($property) {
            return $property !== 'isbn';
        });
        $hydrator->setNamingStrategy(new CompositeNamingStrategy([
            'publishedOn' => new UnderscoreNamingStrategy(),
        ]));
        $hydrator->setStrategy(new CompositeNamingStrategy([
            'published_on' => new DateTimeFormatterStrategy(),
        ]));
        return $hydrator;
    }
}

class AuthorHydratorFactory
{
    public function __invoke(ContainerInterface $container)
    {
        $hydrator = new ObjectProperty();
        $hydrator->setNamingStrategy(new UnderscoreNamingStrategy());
        return $hydrator;
    }
}

You could then compose the HydratorManager service in your own class, and pull these hydrators in order to extract or hydrate instances:

$bookData = $hydrators->get('Acme\BookHydrator')->extract($book);
$authorData = $hydrators->get('Acme\AuthorHydrator')->extract($author);

The DelegatingHydrator works by composing a HydratorPluginManager instance, but has an additional semantic: it uses the class name of the object it is extracting, or the object type to hydrate, as the service name to pull from the HydratorPluginManager. As such, we would change our configuration of the hydrators as follows:

return [
    'hydrators' => [
        'factories' => [
            \Acme\Book::class => \Acme\BookHydratorFactory::class,
            \Acme\Author::class => \Acme\AuthorHydratorFactory::class,
        ],
    ],
];

Additionally, we need to tell our application about the DelegatingHydrator:

// zend-mvc applications:
return [
    'service_manager' => [
        'factories' => [
            \Zend\Hydrator\DelegatingHydrator::class => \Zend\Hydrator\DelegatingHydratorFactory::class
        ]
    ],
];

// Expressive applications
return [
    'dependencies' => [
        'factories' => [
            \Zend\Hydrator\DelegatingHydrator::class => \Zend\Hydrator\DelegatingHydratorFactory::class
        ]
    ],
];

Manually creating the DelegatingHydrator

You can instantiate the DelegatingHydrator manually; when you do, you pass it the `HydratorPluginManager instance.

use Zend\Hydrator\DelegatingHydrator;
use Zend\Hydrator\HydratorPluginManager;

$hydrators = new HydratorPluginManager();
// ... configure the plugin manager ...
$hydrator = new DelegatingHydrator($hydrators);

Technically speaking, the DelegatingHydrator can accept any PSR-11 container to its constructor.

From there, we can inject the DelegatingHydrator into any of our own classes, and use it to extract or hydrate objects:

$bookData = $hydrator->extract($book);
$authorData = $hydrator->extract($author);

This feature can be quite powerful, as it allows you to create the hydration and extraction "recipes" for all of your objects within their own factories, ensuring that anywhere you need them, they operate exactly the same. It also means that for testing purposes, you can simply mock the HydratorInterface (or its parents, ExtractionInterface and HydrationInterface) instead of composing a concrete instance.

Other features

While we've tried to cover the majority of the functionality zend-hydrator provides in this article, it has a number of other useful features:

  • The AggregateHydrator allows you to handle complex objects that implement multiple common interfaces and/or have nested instances composed; it even exposes events you can listen to during each of extraction and hydration. You can read more about it in the documentation.
  • You can write objects that provide and expose their own filters by implementing the Zend\Hydrator\Filter\FilterProviderInterface.
  • You can hydrate or extract arrays of objects by implementing Zend\Hydrator\Iterator\HydratingIteratorInterface.

The component can be seen in use in a number of places: zend-db provides a HydratingResultSet that leverage the HydratorPluginManager in order to hydrate objects pulled from a database. Apigility uses the feature to extract data for Hypertext Application Language (HAL) payloads. We've even seen developers creating custom ORMs for their application using the feature!

What can zend-hydrator help you do today?

Save the date!

Want to learn more about Expressive and Zend Framework? What better location than ZendCon 2017! ZendCon will be hosted 23-26 October 2017 in Las Vegas, Nevada, USA. Visit the ZendCon website for more information.

Source

In our previous two posts, we covered zend-filter and zend-validator. With these two components, you now have the tools necessary to ensure any given user input is valid, fulfilling the first half of the "filter input, escape output" mantra.

However, as we discussed in the zend-validator article, as powerful as validation chains are, they only allow you to validate a single value at a time. How do you go about validating sets of values — such as data submitted from a form, or a resource for an API?

To solve that problem, Zend Framework provides zend-inputfilter. An input filter aggregates one or more inputs, any one of which may also be another input filter, allowing you to validate complex, multi-set, and nested set values.

Installation

To install zend-inputfilter, use Composer:

$ composer require zendframework/zend-inputfilter

zend-inputfilter only directly requires zend-filter, zend-stdlib, and zend-validator. To use its powerful factory feature, however, you'll also need zend-servicemanager, as it greatly simplifies creation of input filters:

$ composer require zendframework/zend-servicemanager

Theory of operation

An input filter composes one or more inputs, any of which may also be an input filter (and thus represent a set of data values).

Any given input is considered required by default, but can be configured to be optional. When required, an input will be considered invalid if the value is not present in the data set, or is empty. When optional, if the value is not present, or is empty, it is considered valid. An additional flag, allow_empty, can be used to allow empty values for required elements; still another flag, continue_if_empty, will force validation to occur for either required or optional values if the value is present but empty.

When validating a value, two steps occur:

  • The value is passed to a filter chain in order to normalize the value. Typical normalizations include stripping non-digit characters for phone numbers and credit card numbers; trimming whitespace; etc.
  • The value is then passed to a validator chain to determine if the normalized value is valid.

An input filter aggregates the inputs, as well as the values themselves. You pass the user input to the input filter after it has been configured, and then check to see if it is valid. If it is, you can pull the normalized values from it (as well as the raw values, if desired). If any value is invalid, you would then pull the validation error messages from it.

Stateless operation

The current approach is stateful: values are passed to the input filter before you execute its isValid() method, and then the values and any validation error messages are stored within the input filter instance for later retrieval. This can cause issues if you wish to use the same input filter multiple times.

For this reason, the planned version 3 release will be stateless: calling isValid() will require passing the value(s) to validate, and both inputs and input filters alike will return a result object from this method with the raw and normalized values, the result of validation, and any validation error messages.

Getting started

Let's consider a registration form where we want to capture a user email and their password. In our first example, we will use explicit usage, which does not require the use of plugin managers.

use Zend\Filter;
use Zend\InputFilter\Input;
use Zend\InputFilter\InputFilter;
use Zend\Validator;

$email = new Input('email');
$email->getFilterChain()
		->attach(new Filter\StringTrim());
$email->getValidatorChain()
		->attach(new Validator\EmailAddress());

$password = new Input('password');
$password->getValidatorChain()
		->attach(new Validator\StringLength(8), true)
	  ->attach(new Validator\Regex('/[a-z]/'))
	  ->attach(new Validator\Regex('/[A-Z]/'))
	  ->attach(new Validator\Regex('/[0-9]/'))
	  ->attach(new Validator\Regex('/[.!@#$%^&*;:]/'));

$inputFilter = new InputFilter();
$inputFilter->add($email);
$inputFilter->add($password);
$inputFilter->setData($_POST);

if ($inputFilter->isValid()) {
    echo "The form is valid\n";
    $values = $inputFilter->getValues();
} else {
    echo "The form is not valid\n";
    foreach ($inputFilter->getInvalidInput() as $error) {
        var_dump($error->getMessages());
    }
}

The above creates two inputs, one each for the incoming email address and password. The email address will be trimmed of whitespace, and then validated. The password will be validated only, checking that we have a value of at least 8 characters, with at least one each of lowercase, uppercase, digit, and special characters. Further, if any given character is missing, we'll get a validation error message so that the user knows how to create their password.

Each input is added to an input filter instance. We pass the form data (via the $_POST superglobal), and then check to see if it is valid. If so, we grab the values from it (we can get the original values via getRawValues()). If not, we grab error messages from it.

By default, all inputs are considered required. Let's say we also wanted to collect the user's full name, but make that optional. We could create an input like the following:

$name = new Input('user_name');
$name->setRequired(false);             // OPTIONAL!
$name>getFilterChain()
		->attach(new Filter\StringTrim());

Input specifications

As noted in the "Installation" section, we can leverage zend-servicemanager and the various plugin managers composed in it in order to create our filters.

Zend\InputFilter\InputFilter internally composes Zend\InputFilter\Factory, which itself composes:

  • Zend\InputFilter\InputFilterPluginManager, a plugin manager for managing Zend\InputFilter\Input and Zend\InputFilter\InputFilter instances.
  • Zend\Filter\FilterPluginManager, a plugin manager for filters.
  • Zend\Validator\ValidatorPluginManager, a plugin manager for validators.

The upshot is that we can often use specifications instead of instances to create our inputs and input filters.

As such, our above examples can be written like this:

use Zend\InputFilter\InputFilter;

$inputFilter = new InputFilter();
$inputFilter->add([
    'name' => 'email',
    'filters' => [
        ['name' => 'StringTrim']
    ],
    'validators' => [
        ['name' => 'EmailAddress']
    ],
]);
$inputFilter->add([
    'name' => 'user_name',
    'required' => false,
    'filters' => [
        ['name' => 'StringTrim']
    ],
]);
$inputFilter->add([
    'name' => 'password',
    'validators' => [
        [
            'name' => 'StringLength',
            'options' => ['min' => 8],
            'break_chain_on_failure' => true,
        ],
        ['name' => 'Regex', 'options' => ['pattern' => '/[a-z]/'],
        ['name' => 'Regex', 'options' => ['pattern' => '/[A-Z]/'],
        ['name' => 'Regex', 'options' => ['pattern' => '/[0-9]/'],
        ['name' => 'Regex', 'options' => ['pattern' => '/[.!@#$%^&*;:]/'],
    ],
]);

There are a number of other fields you could use:

  • type allows you to specify the input or input filter class to use when creating the input.
  • error_message allows you to specify a single error message to return for an input on validation failure. This is often useful as otherwise you'll get an array of messages for each input.
  • allow_empty and continue_if_empty, which were discussed earlier, and control how validation occurs when empty values are encountered.

Why would you do this instead of using the programmatic interface, though?

First, this approach leverages the various plugin managers, which means that any given input, input filter, filter, or validator will be pulled from their respective plugin manager. This allows you to provide additional types easily, but, more importantly, override existing types.

Second, the configuration-based approach allows you to store the definitions in configuration, and potentially even override the definitions via configuration merging! Apigility utilizes this feature heavily.

Managing the plugin managers

To ensure that you can use already configured plugin managers, you can inject them into the Zend\InputFilter\Factory composed in your input filter. As an example, considering the following service factory for an input filter:

function (ContainerInterface $container)
{
    $filters = $container->get('FilterManager');
    $validators = $container->get('ValidatorManager');
    $inputFilters = $container->get('InputFilterManager');

    $inputFilter = new InputFilter();
    $inputFilterFactory = $inputFilter->getFactory();
    $inputFilterFactory->setDefaultFilterChain($filters);
    $inputFilterFactory->setDefaultValidatorChain($validators);
    $inputFilterFactory->setInputFilterManager($inputFilters);

    // add inputs to the $inputFilter, and finally return it...
    return $inputFilter;
}

Managing Input Filters

The InputFilterPluginManager allows you to define input filters with dependencies, which gives you the ability to create re-usable, complex input filters. One key aspect to using this feature is that the InputFilterPluginManager also ensures the configured filter and validator plugin managers are injected in the factory used by the input filter, ensuring any overrides or custom filters and validators you've defined are present.

To make this work, the base InputFilter implementation also implements Zend\Stdlib\InitializableInterface, which defines an init() method; the InputFilterPluginManager calls this after instantiating your input filter and injecting it with a factory composing all the various plugin manager services.

What this means is that if you use this method to add() your inputs and nested input filters, everything will be properly configured!

As an example, let's say we have a "transaction_id" field, and that we need to check if that transaction identifier exists in the database. As such, we may have a custom validator that depends on a database connection to do this. We could write our input filter as follows:

namespace MyBusiness;

use Zend\InputFilter\InputFilter;

class OrderInputFilter extends InputFilter
{
    public function init()
    {
        $this->add([
            'name' => 'transaction_id',
            'validators' => [
                ['name' => TransactionIdValidator::class],
            ],
        ]);
    }
}

We would then register this in our input_filters configuration:

// in config/autoload/input_filters.global.php
return [
    'input_filters' => [
        'invokables' => [
            MyBusiness\OrderInputFilter::class => MyBusiness\OrderInputFilter::class,
        ],
    ],
    'validators' => [
        'factories' => [
            MyBusiness\TransactionIdValidator::class => MyBusiness\TransactionIdValidatorFactory::class,
        ],
    ],
];

This approach works best with the specification form; otherwise you need to pull the various plugin managers from the composed factory and pass them to the individual inputs:

$transId = new Input();
$transId->getValidatorChain()
    ->setValidatorManager($this->getFactory()->getValidatorManager());
$transId->getValidatorChain()
    ->attach(TransactionIdValidator::class);

Specification-driven input filters

Finally, we can look at specification-driven input filters.

The component provides an InputFilterAbstractServiceFactory. When you request an input filter or input that is not directly in the InputFilterPluginManager, this abstract factory will then check to see if a corresponding value is present in the input_filter_specs configuration array. If so, it will pass that specification to a Zend\InputFilter\Factory configured with the various plugin managers in order to create the instance.

Using our original example, we could define the registration form input filter as follows:

return [
    'input_filter_specs' => [
        'registration_form' => [
            [
                'name' => 'email',
                'filters' => [
                    ['name' => 'StringTrim']
                ],
                'validators' => [
                    ['name' => 'EmailAddress']
                ],
            ],
            [
                'name' => 'user_name',
                'required' => false,
                'filters' => [
                    ['name' => 'StringTrim']
                ],
            ],
            [
                'name' => 'password',
                'validators' => [
                    [
                        'name' => 'StringLength',
                        'options' => ['min' => 8],
                        'break_chain_on_failure' => true,
                    ],
                    ['name' => 'Regex', 'options' => ['pattern' => '/[a-z]/'],
                    ['name' => 'Regex', 'options' => ['pattern' => '/[A-Z]/'],
                    ['name' => 'Regex', 'options' => ['pattern' => '/[0-9]/'],
                    ['name' => 'Regex', 'options' => ['pattern' => '/[.!@#$%^&*;:]/'],
                ],
            ],
        ],
    ],
];

We would then retrieve it from the input filter plugin manager:

$inputFilter = $inputFilters->get('registration_form');

Considering most input filters do not need to compose dependencies other than the inputs and input filters they aggregate, this approach makes for a dynamic way to define input validation.

Topics not covered

zend-inputfilter has a ton of other features as well:

  • Input and input filter merging.
  • Handling of array values.
  • Collections (repeated data sets of the same structure).
  • Filtering of file uploads.

On top of all this, it provides a number of interfaces against which you can program in order to write completely custom functionality!

One huge strength of zend-inputfilter is that it can be used for any sort of data set you need to validate: forms, obviously, but also API payloads, data retrieved from a message queue, and more. Let us know what you use it for!

Save the date!

Want to learn more about Expressive and Zend Framework? What better location than ZendCon 2017! ZendCon will be hosted 23-26 October 2017 in Las Vegas, Nevada, USA. Visit the ZendCon website for more information.

Source

In our previous post, we covered zend-filter, The filters in zend-filter are generally used to pre-filter or normalize incoming data. This is all well and good, but we still don't know if the data is valid. That's where zend-validator comes in.

Installation

To install zend-validator, use Composer:

$ composer require zendframework/zend-validator

Like zend-filter, the only required dependency is zend-stdlib. However, a few other components are suggested, based on which filters and/or features you may want to use:

  • zendframework/zend-servicemanager is used by the ValidatorPluginManager and ValidatorChain to look up validators by their short name (versus fully qualified class name), as well as to allow usage of validators with dependencies.
  • zendframework/zend-db is used by a pair of validators that can check if a matching record exists (or does not!).
  • zendframework/zend-uri is used by the Uri validator.
  • The CSRF validator requires both zendframework/zend-math and zendframework/zend-session.
  • zendframework/zend-i18n and zendframework/zend-i18n-resources can be installed in order to provide translation of validation error messages.

For our examples, we'll be using the ValidatorChain functionality with a ValidatorPluginManager, so we will also want to install zend-servicemanager:

$ composer require zendframework/zend-servicemanager

ValidatorInterface

The current incarnation of zend-validator is stateful; validation error messages are stored in the validator itself. As such, validators must implement the ValidatorInterface:

namespace Zend\Validator;

interface ValidatorInterface
{
    /**
     * @param mixed $value
     * @return bool
     */
    public function isValid($value);

    /**
     * @return array
     */
    public function getMessages();
}

The $value can be literally anything; a validator examines it to see if it is valid, and returns a boolean result. If it is invalid, a subsequent call to getMessages() should return an associative array with the keys being message identifiers, and the values the human-readable message strings.

As such, usage looks like the following:

if (! $validator->isValid($value)) {
    // Invalid value
    echo "Failed validation:\n";
    foreach ($validator->getMessages() as $message) {
        printf("- %s\n", $message);
    }
    return false;
}
// Valid value!
return true;

Stateless validations are planned

We are planning to rewrite the zend-validator component for its version 3 release to be stateless. When we do, the ValidatorInterface will be rewritten to have isValid() return a ValidationResult. That instance will provide a method for determining if the validation was successful, encapsulate the value that was validated, and, for invalid values, provide access to the validation error messages. Doing so will allow better re-use of validators within the same execution process.

zend-validator provides a few dozen filters for common operations, including things like:

  • Common conditionals like LessThan, GreaterThan, Identical, NotEmpty, IsInstanceOf, InArray, and Between.
  • String values, such as StringLength, Regex.
  • Network-related values such as Hostname, Ip, Uri, and EmailAddress.
  • Business values such as Barcode, CreditCard, GpsPoint, Iban, and Uuid.
  • Date and time related values such as Date, DateStep, and Timezone.

Any of these validators may be used by themselves.

In many cases, though, your validation may be related to a set of validations: as an example, the value must be non-empty, a certain number of characters, and fulfill a regular expression. Like filters, zend-validator allows you to do this with chains.

ValidatorChain

Usage of a validator chain is similar to filter chains: attach validators you want to execute, and then pass the value to the chain:

use Zend\Validator;

$validator = new Validator\ValidatorChain();
$validator->attach(new Validator\NotEmpty());
$validator->attach(new Validator\StringLength(['min' => 6]));
$validator->attach(new Validator\Regex('/^[a-f0-9]{6,12}$/');

if (! $validator->isValid($value)) {
    // Failed validation
    var_dump($validator->getMessages());
}

The above uses validator instances, eliminating the need for ValidatorPluginManager, and thus avoids usage of zend-servicemanager. However, if we have zend-servicemanager installed, we can replace usage of attach() with attachByName():

use Zend\Validator;

$validator = new Validator\ValidatorChain();
$validator->attachByName('NotEmpty');
$validator->attachByName('StringLength', ['min' => 6]);
$validator->attachByName('Regex', ['pattern' => '/^[a-f0-9]{6,12}$/']);

if (! $validator->isValid($value)) {
    // Failed validation
    var_dump($validator->getMessages());
}

Breaking the chain

If you were to run either of these examples with $value = '', you may discover something unexpected: you'll get validation error messages for every single validator! This seems wasteful; there's no need to run the StringLength or Regex validators if the value is empty, is there?

To solve this problem, when attaching a validator, we can tell the chain to break execution if the given validator fails. This is done by passing a boolean flag:

  • as the second argument to attach()
  • as the third argument to attachByName() (the second argument is an array of constructor options)

Let's update the second example:

use Zend\Validator;

$validator = new Validator\ValidatorChain();
$validator->attachByName('NotEmpty', [], true);
$validator->attachByName('StringLength', ['min' => 6], true);
$validator->attachByName('Regex', ['pattern' => '/^[a-f0-9]{6,12}$/']);

if (! $validator->isValid($value)) {
    // Failed validation
    var_dump($validator->getMessages());
}

The above adds a boolean true as the $breakChainOnFailure argument to the attachByName() method calls of the NotEmpty and StringLength validators (we had to provide an empty array of options for the NotEmpty validator so we could pass the flag). In these cases, if the value fails validation, no further validators will be executed.

Thus:

  • $value = '' will result in a single validation failure message, produced by the NotEmpty validator.
  • $value = 'test' will result in a single validation failure message, produced by the StringLength validator.
  • $value = 'testthis' will result in a single validation failure message, produced by the Regex validator.

Prioritization

Validators are executed in the same order in which they are attached to the chain by default. However, internally, they are stored in a PriorityQueue; this allows you to provide a specific order in which to execute the validators. Higher values execute earlier, while lower values (including negative values) execute last. The default priority is 1.

Priority values may be passed as the third argument to attach() and fourth argument to attachByName().

As an example:

$validator = new Validator\ValidatorChain();
$validator->attachByName('StringLength', ['min' => 6], true, 1);
$validator->attachByName('Regex', ['pattern' => '/^[a-f0-9]{6,12}$/'], false, -100);
$validator->attachByName('NotEmpty', [], true, 100);

In the above, when executing the validation chain, the order will still be NotEmpty, followed by StringLength, followed by Regex.

Why prioritize?

Why would you use this feature? The main reason is if you want to define validation chains via configuration, and cannot guarantee the order in which the items will be present in configuration. By adding a priority value, you can ensure that recreation of the validation chain will preserve the expected order.

Context

Sometimes we may want to vary how we validate a value based on whether or not another piece of data is present, or based on that other piece of data's value. zend-validator offers an unofficial API for that, via an optional $context value you can pass to isValid(). The ValidatorChain accepts this value, and, if present, will pass it to each validator it composes.

As an example, let's say you want to capture an email address (form field "contact"), but only if the user has selected a radio button allowing you to do so (form field "allow_contact"). We might write that validator as follows:

use ArrayAccess;
use ArrayObject;
use Zend\Validator\EmailAddress;
use Zend\Validator\ValidatorInterface;

class ContactEmailValidator implements ValidatorInterface
{
    const ERROR_INVALID_EMAIL = 'contact-email-invalid';

    /** @var string */
    private $contextVariable;

    /** @var EmailAddress */
    private $emailValidator;

    /** @var string[] */
    private $messages = [];

    /** @var string[] */
    private $messageTemplates = [
        self::ERROR_INVALID_EMAIL => 'Email address "%s" is invalid',
    ];

    public function __construct(
        EmailAddress $emailValidator = null,
        string $contextVariable = 'allow_contact'
    ) {
        $this->emailValidator = $emailValidator ?: new EmailAddress();
        $this->contextVariable = $contextVariable;
    }

    public function isValid($value, $context = null)
    {
        $this->messages = [];

        if (! $this->allowsContact($context)) {
            // Value will be discarded, so always valid.
            return true;
        }

        if ($this->emailValidator->isValid($value)) {
            return true;
        }

        $this->messages[self::ERROR_INVALID_EMAIL] = sprintf(
            $this->messageTemplates[self::ERROR_INVALID_EMAIL],
            var_export($value, true)
        );
        return false;
    }

    public function getMessages()
    {
        return $this->messages;
    }

    private function allowsContact($context) : bool
    {
        if (! $context ||
            ! (is_array($context)
              || $context instanceof ArrayObject
              || $context instanceof ArrayAccess)
        ) {
            return false;
        }

        $allowsContact = $context[$this->contextVariable] ?? false;

        return (bool) $allowsContact;
    }
}

We would then add it to the validator chain, and call it like so:

$validator->attach(new ContactEmailValidator());
if (! $validator->isValid($data['contact'], $data)) {
    // Failed validation!
}

This approach can allow for some quite complex validation routines, particularly if you nest validation chains within custom validators!

Registering your own validators.

If you write your own validators, chances are you'll want to use them with the ValidatorChain. This class composes a ValidatorPluginManager, which is a plugin manager built on top of zend-servicemanager. As such, you can register your validators with it:

$plugins = $validator->getPluginManager();
$plugins->setFactory(ContactEmailValidator::class, ContactEmailValidatorFactory::class);
$plugins->setService(ContactEmailValidator::class, $contactEmailValidator);

Alternately, if using zend-mvc or Expressive, you can provide configuration via the validators configuration key:

return [
    'validators' => [
        'factories' => [
            ContactEmailValidator::class => ContactEmailValidatorFactory::class,
        ],
    ],
];

If you want to use a "short name" to identify your validator, we recommend using an alias, aliasing the short name to the fully qualified class name.

Wrapping up

Between using zend-filter to normalize and pre-filter values, and zend-validator to validate the values, you can start locking down the input your users submit to your application.

That said, what we've demonstrated so far is how to work with single values. Most forms submit sets of values; using the approaches so far can lead to a lot of code!

We have a solution for this as well, via our zend-inputfilter component, which we'll be detailing in our next post!

Save the date!

Want to learn more about Expressive and Zend Framework? What better location than ZendCon 2017! ZendCon will be hosted 23-26 October 2017 in Las Vegas, Nevada, USA. Visit the ZendCon website for more information.

Source

When securing your website, the mantra is "Filter input, escape output." We previously covered escaping output with our post on zend-escaper. We're now going to turn to filtering input.

Filtering input is rather complex, and spans a number of practices:

  • Filtering/normalizing input. As an example, your web page may have a form that allows submitting a credit card number. These have a variety of formats that may include spaces or dashes or dots — but the only characters that are of importance are the digits. As such, you will want to normalize such input to strip out the unwanted characters.
  • Validating input. Once you have done such normalization, you can then check to see that the data is actually valid for its context. This may include one or more rules. Using our credit card example, you might first check it is of an appropriate length, and then verify that it begins with a known vendor digit, and only after those pass, validate the number against a online service.

For now, we're going to look at the first item, filtering and normalizing input, using the component zend-filter.

Installation

To install zend-filter, use Composer:

$ composer require zendframework/zend-filter

Currently, the only required dependency is zend-stdlib. However, a few other components are suggested, based on which filters and/or featurse you may want to use:

  • zendframework/zend-servicemanager is used by the FilterChain component for looking up filters by their short name (versus fully qualified class name).
  • zendframework/zend-crypt is used by the encryption and decryption filters.
  • zendframework/zend-uri is used by the UriNormalize filter.
  • zendframework/zend-i18n is used by several filters that provide internationalization features.

For our examples, we'll be using the FilterChain functionality, so we will also want to install zend-servicemanager:

$ composer require zendframework/zend-servicemanager

FilterInterface

Filters can be one of two things: a callable that accepts a single argument (the value to filter), or an instance of Zend\Filter\FilterInterface:

namespace Zend\Filter;

interface FilterInterface
{
    public function filter($value);
}

The value can be literally anything, and the filter can return anything itself. Generally speaking, if a filter cannot operate on the value, it is expected to return it verbatim.

zend-filter provides a few dozen filters for common operations, including things like:

  • Normalizing strings, integers, etc. to their corresponding boolean values.
  • Normalizing strings representing integers to integer values.
  • Normalizing empty values to null values.
  • Normalizing input sets representing date and/or time selections from forms to DateTime instances.
  • Normalizing URI values.
  • Comparing values to whitelists and blacklists.
  • Trimming whitespace, stripping newlines, and removing HTML tags or entities.
  • Upper and lower casing words.
  • Stripping everything but digits.
  • Performing PCRE regexp replacements.
  • Word inflection (camel-case to underscores and vice versa, etc.).
  • Decrypting and encrypting file contents, as well as casting file contents to lower or upper case.
  • Compressing and decompressing values.
  • Decrypting and encrypting values.

Any of these may be used by themselves. However, in most cases, if that's all you're doing, you might as well just do the functionality inline. So, what's the benefit of zend-filter?

Chaining filters!

FilterChain

When we get input from the web, it generally comes as strings, and is the result of user input. As such, we often get a lot of garbage: extra spaces, unnecessary newlines, HTML characters, etc.

When filtering such input, we might want to perform several operations:

$value = $request->getParsedBody()['phone'] ?? '';
$value = trim($value);
$value = preg_replace("/[^\n\r]/", '', $value);
$value = preg_replace('/[^\d]/', '', $value);

We then need to test our code to ensure that we're filtering correctly. Additionally, if at any point we fail to re-assign, we may lose the changes we were performing!

With zend-filter, we can instead use a FilterChain. The above example becomes:

use Zend\Filter\FilterChain;

$filter = new FilterChain();
// attachByName uses the class name, minus the namespace, and 
$filter->attachByName('StringTrim');
$filter->attachByName('StripNewlines');
$filter->attachByName('Digits');
$value = $filter->filter($request->getParsedBody()['phone'] ?? '');

Here's another example: let's say we have configuration keys that are in snake_case_format, and which may be read from a file, and we wish to convert those values to CamelCase.

use Zend\Filter;

$filter = new Filter\FilterChain();
// attach lets you provide the instance you wish to use; this will work
// even without zend-servicemanager installed.
$filter->attach(new Filter\StringTrim());
$filter->attach(new Filter\StripNewlines()); // because we may have \r characters
$filter->attach(new Filter\Word\UnderscoreToCamelCase());

$configKeys = array_map([$filter, 'filter'], explode("\n", $fileContents));

This new example demonstrates a key feature of a FilterChain: you can re-use it! Instead of having to put the code for normalizing the values within an array_map callback, we can instead directly use our already configured FilterChain, invoking it once for each value!

Wrapping up

zend-filter can be a powerful tool in your arsenal for dealing with user input. Paired with good validation, you can protect your application from malicious or malformed input.

In the next post, we'll discuss zend-validation!

Save the date!

Want to learn more about Expressive and Zend Framework? What better location than ZendCon 2017! ZendCon will be hosted 23-26 October 2017 in Las Vegas, Nevada, USA. Visit the ZendCon website for more information.

Source