Giter VIP home page Giter VIP logo

laminas-diactoros's Introduction

laminas-diactoros

Build Status type-coverage Psalm level

🇷🇺 Русским гражданам

Мы, участники Laminas, родились и живем в разных странах. У многих из нас есть друзья, родственники и коллеги как в России, так и в Украине. Некоторые из нас родились в России. Некоторые из нас живут в России. У некоторых бабушки и дедушки сражались с фашистами во Второй мировой войне. Здесь никто не поддерживает фашизм.

У одного из нас есть украинская родственница, которая спаслась из дома вместе с сыном. Поезд задержался из-за бомбежки на дороге впереди. У нас есть друзья, которые прячутся в бомбоубежищах. Мы с тревогой ждем весточки от них после воздушных налетов, которые беспорядочно наносят удары и попадают по больницам, школам, детским садам и домам. Мы не берем это из каких-либо СМИ. Мы наблюдаем это напрямую.

Вы доверяете нам достаточно, чтоб использовать наши программы, и мы просим вас довериться нам вновь. Мы нуждаемся в помощи. Выходите и протестуйте против этой бесполезной войны. Остановите кровопролитие. Скажите "Нет войне!"

🇺🇸 To Citizens of Russia

We at Laminas come from all over the world. Many of us have friends, family and colleagues in both Russia and Ukraine. Some of us were born in Russia. Some of us currently live in Russia. Some have grandparents who fought Nazis in World War II. Nobody here supports fascism.

One team member has a Ukrainian relative who fled her home with her son. The train was delayed due to bombing on the road ahead. We have friends who are hiding in bomb shelters. We anxiously follow up on them after the air raids, which indiscriminately fire at hospitals, schools, kindergartens and houses. We're not taking this from any media. These are our actual experiences.

You trust us enough to use our software. We ask that you trust us to say the truth on this. We need your help. Go out and protest this unnecessary war. Stop the bloodshed. Say "stop the war!"

Diactoros (pronunciation: /dɪʌktɒrɒs/): an epithet for Hermes, meaning literally, "the messenger."

This package supercedes and replaces phly/http.

laminas-diactoros is a PHP package containing implementations of the PSR-7 HTTP message interfaces and PSR-17 HTTP message factory interfaces.

Documentation

Documentation is available at:

Source files for documentation are in the docs/ tree.


Contributing and Support

laminas-diactoros's People

Contributors

admad avatar boesing avatar ezimuel avatar fcabralpacheco avatar franzliedke avatar froschdesign avatar ghostwriter avatar gsteel avatar hannesvdvreken avatar harikt avatar heiglandreas avatar koopzington avatar laminas-bot avatar localheinz avatar maks3w avatar michalbundyra avatar mtymek avatar mwillbanks avatar ocramius avatar oscarotero avatar pine3ree avatar renovate[bot] avatar samsonasik avatar seriousken avatar settermjd avatar snapshotpl avatar stefanotorresi avatar timwolla avatar weierophinney avatar xerkus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laminas-diactoros's Issues

Handle request headers with numeric keys

Here, at getpocket.com, we have had a client hit our servers with header keys as integers. In doing so HeaderSecurity::assertValidName is throwing an exception because ! is_string(-1) === true.

I have been unable to identify any documentation which would suggest that these values could be valid. At this point I believe the best behavior is to ignore these keys.


Originally posted by @jeshuaborges at zendframework/zend-diactoros#286

BC Break, Laravel Passport 7.5 -> 8.3

I originally opened this ticket with the passport team and they asked me to re-open it over here. The problem happens on passport upgrade, but if you look at the stack trace, you should see that the error message is from symfony/psr-http-message-bridge complaining that a Diactoros method isn't returning the correct value.

  • Passport Version: 8.3.1
  • Laravel Version: 6.9.0
  • PHP Version: 7.4.0
  • Database Driver & Version: MySQL

Description:

After upgrading from passport 7.5.1 -> 8.3.1, with no other changes, a client token request crashes with this error:

device-service-fpm_1    | [2020-02-03 13:56:30] local.ERROR: Return value of Zend\Diactoros\normalizeServer() must be of the type array, none returned {"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalThrowableError(code: 0): Return value of Zend\\Diactoros\
device-service-fpm_1    | ormalizeServer() must be of the type array, none returned at /var/www/device-service/vendor/laminas/laminas-diactoros/src/functions/normalize_server.legacy.php:22)
device-service-fpm_1    | [stacktrace]
device-service-fpm_1    | #0 /var/www/device-service/vendor/symfony/psr-http-message-bridge/Factory/DiactorosFactory.php(52): Zend\\Diactoros\
device-service-fpm_1    | ormalizeServer()
device-service-fpm_1    | #1 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/RoutingServiceProvider.php(131): Symfony\\Bridge\\PsrHttpMessage\\Factory\\DiactorosFactory->createRequest()
device-service-fpm_1    | #2 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\Routing\\RoutingServiceProvider->Illuminate\\Routing\\{closure}()
device-service-fpm_1    | #3 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build()
device-service-fpm_1    | #4 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Container\\Container->resolve()
device-service-fpm_1    | #5 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(769): Illuminate\\Container\\Container->make()
device-service-fpm_1    | #6 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php(79): Illuminate\\Foundation\\Application->make()
device-service-fpm_1    | #7 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php(46): Illuminate\\Routing\\ControllerDispatcher->transformDependency()
device-service-fpm_1    | #8 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php(27): Illuminate\\Routing\\ControllerDispatcher->resolveMethodDependencies()
device-service-fpm_1    | #9 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(41): Illuminate\\Routing\\ControllerDispatcher->resolveClassMethodDependencies()
device-service-fpm_1    | #10 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch()
device-service-fpm_1    | #11 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()
device-service-fpm_1    | #12 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()
device-service-fpm_1    | #13 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}()
device-service-fpm_1    | #14 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(59): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
device-service-fpm_1    | #15 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\\Routing\\Middleware\\ThrottleRequests->handle()
device-service-fpm_1    | #16 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
device-service-fpm_1    | #17 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then()
device-service-fpm_1    | #18 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack()
device-service-fpm_1    | #19 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute()
device-service-fpm_1    | #20 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Routing/Router.php(613): Illuminate\\Routing\\Router->dispatchToRoute()
device-service-fpm_1    | #21 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): Illuminate\\Routing\\Router->dispatch()
device-service-fpm_1    | #22 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}()
device-service-fpm_1    | #23 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
device-service-fpm_1    | #24 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
device-service-fpm_1    | #25 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
device-service-fpm_1    | #26 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
device-service-fpm_1    | #27 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
device-service-fpm_1    | #28 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle()
device-service-fpm_1    | #29 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(62): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
device-service-fpm_1    | #30 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle()
device-service-fpm_1    | #31 /var/www/device-service/vendor/fideloper/proxy/src/TrustProxies.php(57): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
device-service-fpm_1    | #32 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Fideloper\\Proxy\\TrustProxies->handle()
device-service-fpm_1    | #33 /var/www/device-service/vendor/barryvdh/laravel-cors/src/HandlePreflight.php(29): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
device-service-fpm_1    | #34 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Barryvdh\\Cors\\HandlePreflight->handle()
device-service-fpm_1    | #35 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
device-service-fpm_1    | #36 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then()
device-service-fpm_1    | #37 /var/www/device-service/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter()
device-service-fpm_1    | #38 /var/www/device-service/public/index.php(55): Illuminate\\Foundation\\Http\\Kernel->handle()
device-service-fpm_1    | #39 {main}
device-service-fpm_1    | "}

Steps To Reproduce:

  1. Upgrade laravel/passport to 8.3.1.
  2. Make an /oauth/token request using a client token. Request fails.
  3. Revert laravel/passport to 7.5.1.
  4. Repeat same token request. Request succeeds.

Can UploadedFile extend SplFileInfo ?

Is there a particular reason that UploadedFile does not extend SplFileInfo. The only conflicting interface, which isn't even really a conflict so much is getSize() -- would there be any interest in this? I can do a PR if the interest is there.

I need this feature like yesterday and without it I'm either gonna need to look for an alternative or fork.


Originally posted by @mattsah at zendframework/zend-diactoros#377

PHP 8.0 support

Feature Request

Q A
New Feature yes

Summary

To be prepared for the december release of PHP 8.0, this repository has some additional TODOs to be tested against the new major version.

In order to make this repository compatible, one has to follow these steps:

  • Modify composer.json to provide support for PHP 8.0 by adding the constraint ~8.0.0
  • Modify composer.json to drop support for PHP less than 7.3
  • Modify composer.json to implement phpunit 9.3 which supports PHP 7.3+
  • Modify .travis.yml to ignore platform requirements when installing composer dependencies (simply add --ignore-platform-reqs to COMPOSER_ARGS env variable)
  • Modify .travis.yml to add PHP 8.0 to the matrix (NOTE: Do not allow failures as PHP 8.0 has a feature freeze since 2020-08-04!)
  • Modify source code in case there are incompatibilities with PHP 8.0

Conflict with zend-diactoros

Bug Report

Q A
Version(s) 1.8.7p2

Summary

zend-diactoros and laminas-diactoros define the same function in the same namespace. This can lead to PHP fatal errors when both are installed in the same project. It seems like either this conflict should be resolved (i.e. by fixing the namespace or function name), or laminas-diactoros should formally declare a conflict with the older zend-diactoros in composer.json.

Current behavior

When running PHPUnit on our own downstream project, an error is thrown:

PHP Fatal error: Cannot redeclare Zend\Diactoros\createUploadedFile() (previously declared in /home/travis/build/acquia/blt/vendor/zendframework/zend-diactoros/src/functions/create_uploaded_file.php:20) in /tmp/blt-sandbox-instance/vendor/laminas/laminas-diactoros/src/functions/create_uploaded_file.legacy.php on line 19

How to reproduce

I haven't figured out a more minimal way to reproduce this yet, but you can see it failing in our tests above.

Expected behavior

laminas-diactoros and zend-diactoros should be able to be installed side-by-side without conflict, or there should be a formal Composer dependency preventing them from being installed simultaneously.

SapiEmitter::emitBody() suppresses exceptions by using StreamInterface::__toString()

SapiEmitter::emitBody() is currently:

echo $response->getBody();

The definition of StreamInterface::__toString() specifies:

This method MUST NOT raise an exception in order to conform with PHP's string casting operations.

and Zend\Diactoros\Stream::__toString() indeed suppresses run-time exceptions:

try {
    $this->rewind();
    return $this->getContents();
} catch (RuntimeException $e) {
    return '';
}

GuzzleHttp\Psr7\Stream::__toString() even suppresses all exceptions:

try {
    $this->seek(0);
    return (string) stream_get_contents($this->stream);
} catch (\Exception $e) {
    return '';
}

As a practical result of this, whenever there is an exception in the process of reading the stream, instead of it bubbling up to the next matching catch block or to the exception handler to notify the developer, the HTTP client gets an empty response instead. In other words, an error which the developer could have been notified of directly via their error reporting system is instead translated into something the user must report manually. I don't want to wait for our users to submit bugs when they see a white page. I want errors going to our error reporting system wherever possible (currently Bugsnag) so we know about it immediately.

I don't know what "conform with PHP's string casting operations means", but I did find this:

Johannes explained that there is no way to ensure that an exception thrown during a cast to string would be handled correctly by the Zend Engine, and that this won't change unless large parts of the Engine are rewritten.

So it seems to me, __toString() in PHP is basically broken when it comes to exceptions. Either you allow it to throw exceptions, in which case they don't bubble and you get a fatal error instead, or you suppress the exceptions and turn them into a broken result which the user has to report. Neither are ideal.

I therefore propose that SapiEmitter::emitBody() not depend on __toString() and instead be:

$stream = $response->getBody();
if ($stream->isSeekable()) {
    $stream->rewind();
}
echo $stream->getContents();

Do you think this would be a good idea?


Originally posted by @jesseschalken at zendframework/zend-diactoros#181

`ServerRequestFactory::fromGlobals()` checks if args are truthy rather than set

In ServerRequestFactory::fromGlobals(), most of the code checks if the arguments are truthy, rather than set. For example:

https://github.com/zendframework/zend-diactoros/blob/89d471cc09850c7d47839cf16ba7a1fed54d45e5/src/ServerRequestFactory.php#L57-L58

https://github.com/zendframework/zend-diactoros/blob/89d471cc09850c7d47839cf16ba7a1fed54d45e5/src/ServerRequestFactory.php#L72-L74

This becomes an issue during testing (or a long-running process that accepts multiple requests). For example:

// In a previous test
$_POST = ['foo' => 'bar'];

// In current test
$request = ServerRequestFactory::fromGlobals(null, null, []);
echo serialize($request->getParsedBody());
// Expected: a:0:{}
// Actual: a:1:{s:3:"foo";s:3:"bar";}

Improved versions would be:

        $server  = static::normalizeServer($server ?? $_SERVER); 
        $files   = static::normalizeFiles($files ?? $_FILES); 
            $cookies ?? $_COOKIE, 
            $query ?? $_GET, 
            $body ?? $_POST, 

Or for under PHP 7:

        $server  = static::normalizeServer(isset($server) ? $server : $_SERVER); 
        $files   = static::normalizeFiles(isset($files) ? $files : $_FILES); 
            isset($cookies) ? $cookies : $_COOKIE, 
            isset($query) ? $query : $_GET, 
            isset($body) ? $body : $_POST, 

(This code should fix the issues, but I didn't have time to write any tests right now, so I'm opening an issue instead of a pr.)


Originally posted by @0b10011 at zendframework/zend-diactoros#281

UTF-8 URIs are broken by parse_url when locale is set

The parse_url function is not multibyte safe, and was never designed to be, which seems to be why this bug from 2010 has still not been addressed. As mentioned in the comments on that bug, a nicer behaviour would be for parse_url to "treat all extended characters ... as opaque characters and copy them as-is without modification", but I don't see that happening any time soon.

There are a couple of options I can think of to try and support UTF8 URIs in this library;

  • Use a wrapper for parse_url which URL encodes/decodes extended characters (e.g. in this comment from the manual page)
  • Manually parse the URL in PHP without parse_url

Or alternatively this library could simply reject URI's with extended characters which aren't properly encoded, as they are technically invalid according to RFC 3986.

Whichever way, it might be worth adding something to the Travis config to run the tests under different locale environments to show how this is reproduced in the unit tests (though this might be a pain, since the available values for the locale are platform dependent).

Originally posted by @Pudge601 in zendframework/zend-diactoros#155 (comment)


Originally posted by @Pudge601 at zendframework/zend-diactoros#354

Request target is invalid when uri path is empty

::getRequestTarget()

http://tools.ietf.org/html/rfc7230#section-5.3.1

The most common form of request-target is the origin-form.
origin-form = absolute-path [ "?" query ]

The query component is optional, the path is required.
But in code if exists only query - return it

        $target = $this->uri->getPath();
        if ($this->uri->getQuery()) {
            $target .= '?' . $this->uri->getQuery();
        }
        if (empty($target)) {
            $target = '/';
        }

probably it would be correct:

        $target = $this->uri->getPath();
        if (! $target) {
            $target = '/';
        }
        if ($this->uri->getQuery()) {
            $target .= '?' . $this->uri->getQuery();
        }
        return $target;

Originally posted by @easy-system at zendframework/zend-diactoros#153

Probably an incorrect test case testAuthorityIsPrefixedByDoubleSlashIfPresent in UriTest.php

Two tests are looking identical despite description. Probably withHost in second case should be replaced by something else.

    public function testUriDoesNotAppendColonToHostIfPortIsEmpty()
    {
        $uri = (new Uri())->withHost('google.com');
        $this->assertSame('//google.com', (string) $uri);
    }
    public function testAuthorityIsPrefixedByDoubleSlashIfPresent()
    {
        $uri = (new Uri())->withHost('example.com');
        $this->assertSame('//example.com', (string) $uri);
    }

Originally posted by @Keksov at zendframework/zend-diactoros#381

Allow using serializers with other PSR implementations

Feature Request

Q A
New Feature yes
RFC no
BC Break no

Summary

Hey there 👋

I'm working on a project that could use the Laminas\Diactoros\Request\ArraySerializer and Laminas\Diactoros\Response\ArraySerializer. However I don't want to force the users of my package to use the laminas-diactoros PSR-7 implementation.

Any chance the serializers could be altered to use the PSR-17 factories and extracted to a separate package? I.e. something like this:

<?php

declare(strict_types=1);

namespace Laminas\Diactoros\Serializer;

use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\RequestInterface;
use Throwable;

use function sprintf;

final class ArraySerializer
{
    private RequestFactoryInterface $requestFactory;

    private StreamFactoryInterface $streamFactory;

    public function __construct(
        \Psr\Http\Message\RequestFactoryInterface $requestFactory,
        \Psr\Http\Message\StreamFactoryInterface $streamFactory
    ) {
        $this->requestFactory = $requestFactory;
        $this->streamFactory = $streamFactory;
    }


    public static function toArray(RequestInterface $request) : array
    {
        // ...
    }

    public function fromArray(array $serializedRequest) : RequestInterface
    {
        $uri = self::getValueFromKey($serializedRequest, 'uri');
        $method = self::getValueFromKey($serializedRequest, 'method');
        $request = $this->requestFactory->createRequest($method, $uri);
        $body = $this->streamFactory->createStream(self::getValueFromKey($serializedRequest,
                'body'));
        // ...
    }
}

Thanks!

LTS Version 1.7 is missing a security fix

  • I was not able to find an open or closed issue matching what I'm seeing.
  • This is not a question. (Questions should be asked on chat (Signup here) or our forums.)

According to https://framework.zend.com/long-term-support 1.7 is the long term support version of zend-diactoros, however the Symfony security scanner shows that 1.7.2 is missing the fix for the URL Rewrite vulnerability [CVE-NONE-0001]: https://framework.zend.com/security/advisory/ZF2018-01

I've tried to be helpful and backport this in https://github.com/alexpott/zend-diactoros/tree/1.7.x-CVE-NONE-0001 but I can't create a PR because there is no 1.7 release branch.

Code to reproduce the issue

        $server = [
            'REQUEST_URI' => 'https://example.com/requested/path',
            'HTTP_X_ORIGINAL_URL' => '/hijack-attempt'
        ];
        $path = ServerRequestFactory::marshalRequestUri($server);

Expected results

        $path === '/requested/path';

Actual results

        $path === '/hijack-attempt';

Originally posted by @alexpott at zendframework/zend-diactoros#373

Add support for Responses that produce a HTTP/1.1 chunked stream

HTTP/1.1 provides 'Transfer-encoding: chunked' for sending a stream of data from the server.

Zend Diactoros currently doesn't seem to provide out-of-the-box support for this.

  • There's no existing Response that sets the required headers for you.
  • There's no existing implementation of StreamInterface that supports dynamic content and is compatible with the requirements of SapiStreamEmitter.

Possible solution for out-of-the-box support could be:

  • Add a DynamicStreamInterface interface that extends StreamInterface, for type-hinting in a moment
  • Add a GeneratorStream class that implements DynamicStreamInterface, and its read() method gets the required data from a PHP generator
  • Add another class that implements DynamicStreamInterface, and its read() method gets the required data from a PHP callback
  • Add a StreamResponse class that requires a DynamicStreamInterface in the constructor, sets the necessary headers for chunked stream delivery

It leaves questions around handling $maxBufferLength, and where the code goes to write the actual chunked blocks (trait? helper class?).

I have to build a solution for this, and I'm happy to contribute it back to Diactoros, if we can agree a design :)


Originally posted by @stuartherbert at zendframework/zend-diactoros#261

Low performance of TextResponse and another related responses

Feature Request

Q A
New Feature no
RFC no
BC Break no

Summary

Currently TextResponse always allocating new buffer for string output - https://github.com/laminas/laminas-diactoros/blob/2.6.x/src/Response/TextResponse.php#L75
This approach working really slow, my suggestion is to implement pure RAM string stream.
Here is what I mean - https://github.com/makise-co/framework/blob/master/src/Http/FakeStream.php (this approach is ~30% more performant)

ServerRequestFactory

This all works fine. Great.
But why all the logic is concentrated in one place?
Moreover, there is a class of Server.
I think it would be better to make a directory of the factories.
Firstly, it allows to separate each logic element in its factory.
Secondly, because I can always get in the code of the original values.
For example, Zend\Diactoros\Factory\HttpProtocolFactory:

use UnexpectedValueException;

class HttpProtocolFactory
{
    public static function make(array $server = null)
    {
        if (empty($server)) {
            $server = $_SERVER;
        }

        if (! isset($server['SERVER_PROTOCOL'])) {
            return '1.1';
        }

        $protocol = $server['SERVER_PROTOCOL'];

        if (! preg_match('#\A(?:HTTP/)?(?P<version>\d{1}\.\d+)\Z#', $protocol, $matches)) {
            throw new UnexpectedValueException(sprintf(
                'Unrecognized protocol version "%s".',
                $server['SERVER_PROTOCOL']
            ));
        }

        return $matches['version'];
    }
}

All this is true for the request method, headers, Uri, uploaded files etc


Originally posted by @easy-system at zendframework/zend-diactoros#158

Environment variables prefixed with `CONTENT_` may overwrite HTTP-Headers provided by the client

Bug Report

Q A
Version(s) all

Summary

Environment variables prefixed with CONTENT_ may overwrite HTTP-Headers provided by the client

Current behavior

This may be entirely expected behavior but I have not found a spec or warning in the documentation.
It's a least surprising to find unrelated environment variables as request header and potentially a security problem when comparing the env-variable against the header during authentication.

Environment variables prefixed with CONTENT_ will be populated as http-headers:

I stumbled about this behavior in a project with the following .env-file:

CONTENT_API_PASSWORD=password-for-content-api

The .env file is loaded into the $_SERVER superglobal via Dotenv\Dotenv::createImmutable().

The request object is created via \Laminas\Diactoros\ServerRequestFactory::fromGlobals.
The request object now contains content-api-password as request-header $request->getHeader('content-api-password').

Environment variables prefixed with CONTENT_ max overwrite client provided HTTP-Headers:

If the same header name is provided by an http-client the $_SERVER superglobal contains a HTTP_CONTENT_API_PASSWORD key.

In the current implementation the order is relevant. Whatever key is defined later in $_SERVER will be used to populate the HTTP-Header.

How to reproduce

        $server = [
            'HTTP_CONTENT_API_PASSWORD' => 'password_from_header',
            'CONTENT_API_PASSWORD' => 'password_from_env',
        ];

        $request = ServerRequestFactory::fromGlobals($server);

        $this->assertSame('password_from_env', $request->getHeader('content-api-password')[0]);


        $server = [
            'CONTENT_API_PASSWORD' => 'password_from_env',
            'HTTP_CONTENT_API_PASSWORD' => 'password_from_header',
        ];

        $request = ServerRequestFactory::fromGlobals($server);

        $this->assertSame('password_from_header', $request->getHeader('content-api-password')[0]);

Expected behavior

        $server = [
            'HTTP_CONTENT_API_PASSWORD' => 'password_from_header',
            'CONTENT_API_PASSWORD' => 'password_from_env',
        ];

        $request = ServerRequestFactory::fromGlobals($server);

        $this->assertSame('password_from_header', $request->getHeader('content-api-password')[0]);


        $server = [
            'CONTENT_API_PASSWORD' => 'password_from_env',
            'HTTP_CONTENT_API_PASSWORD' => 'password_from_header',
        ];

        $request = ServerRequestFactory::fromGlobals($server);

        $this->assertSame('password_from_header', $request->getHeader('content-api-password')[0]);

exception not a valid header name

Not sure what is going on? Could it be http2 related?

generated by: It's comes Charles's "Copy Curl Request" feature

curl -H ':method: POST' -H ':scheme: https' -H ':path: /identity/update-display-name' -H ':authority: api-development.plhw.nl' -H 'accept: application/json, text/javascript, */*; q=0.01' -H 'content-type: application/json; charset=UTF-8' -H 'origin: http://localhost:4200' -H 'accept-encoding: gzip, deflate' -H 'content-length: 72' -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7' -H 'referer: http://localhost:4200/account/settings' -H 'dnt: 1' -H 'accept-language: en-us' --data-binary '{"user_id":"6fc88c51-c16a-4612-9b8b-e48e15931689","display_name":"BasK"}' 'https://api-development.plhw.nl/identity/update-display-name' | gunzip

Errors with:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   479  100   407  100    72    970    171 --:--:-- --:--:-- --:--:--   973
<br />
<b>Fatal error</b>:  Uncaught InvalidArgumentException: &quot;&quot; is not valid header name in /home-projects/api-plhw-development/deploy/releases/20160529202409UTC/vendor/zendframework/zend-diactoros/src/HeaderSecurity.php:150
Stack trace:
#0 /home-projects/api-plhw-development/deploy/releases/20160529202409UTC/vendor/zendframework/zend-diactoros/src/RequestTrait.php(329): Zend\Diactoros\HeaderSecurity::assertValidName('')
#1 /home-projects/api-plhw-development/deploy/releases/20160529202409UTC/vendor/zendframework/zend-diactoros/src/RequestTrait.php(70): Zend\Diactoros\ServerRequest-&gt;assertHeaders(Array)
#2 /home-projects/api-plhw-development/deploy/releases/20160529202409UTC/vendor/zendframework/zend-diactoros/src/ServerRequest.php(96): Zend\Diactoros\ServerRequest-&gt;initialize(Object(Zend\Diactoros\Uri), 'POST', Object(Zend\Diactoros\PhpInputStream), Array)
#3 /home-projects/api-plhw-development/deploy/releases/20160529202409UTC/vendor/zendframework/zend-diactoros/src/ServerRequestFactory.php(73): Zend\Diactoros\ServerRequest-&gt;__const in <b>/home-projects/api-plhw-development/deploy/releases/20160529202409UTC/vendor/zendframework/zend-diactoros/src/HeaderSecurity.php</b> on line <b>150</b><br />

Originally posted by @basz at zendframework/zend-diactoros#198

`strict_types` Breaks Consuming Code

Note: This could be totally intentional, and it was for a major version, so not a problem. But wanted to make sure this was the intention. I don't think it was as the change log doesn't mention it as a breaking change, or even reference the potential issue:

zendframework/zend-diactoros#329 adds return type hints and scalar parameter type hints wherever possible. The changes were done to help improve code quality, in part by reducing manual type checking. If you are extending any classes, you may need to update your signatures; check the signatures of the class(es) you are extending for changes.

BC Break Report

Q A
Version 2.x.x

Summary

Because strict_types are enabled in the library, but method arguments lack type hints (due to the interface understandably not type hinting arguments), Stream::write($string) and other methods accept values that can be juggled into the expected type (and were in the past), but now are rejected by the underlying f*() methods with a TypeError:

Previous behavior

$stream->write(false); // would write ''

Current behavior

$stream->write(false); // throws TypeError
TypeError : fwrite() expects parameter 2 to be string, bool given

How to reproduce

See my branch for a test / fix specific to write(); however, there are many other methods that have the same behavior.

We fixed on our end, I just wanted to make sure this behavior was known / documented.

Error with HTTP2 and NGINX

Bug Report

Q A
Version(s) 2.5.0

Summary

Laminas\Diactoros\Exception\InvalidArgumentException: Unsupported HTTP protocol version "2.0" provided exception when enabling http2 on nginx as it passes a protocol of HTTP/2.0

Current behavior

How to reproduce

Enable http2 on nginx (Current version tested is 1.21.1)

Expected behavior

No error with HTTP/2.0

Multiple use of the UploadedFile object in PHPUnit test cases with the same file results in errors - File is consumed

Bug Report

Q A
Version(s) 2.2.2

Summary

Hi,

I use the UploadedFile object to make my PHPUnit test cases more realistic for my application. (See example below) After an update of the
laminas-diactoros framework, I noticed that many PHPUnit test cases no longer work. This is because the UploadedFile object deletes the original file after use. See commit link: 197f195#commitcomment-77930965

If this is not a bug, is there an alternative to creating an UploadedFile object without the object deleting the file?

Danger! This only applies if multiple PHPUnit test cases that want to use the same file to test a function.

Example

public function testAddAuthorizedPostDataOKActiveTrue(): void {
		$data = array(
			'active' => true,
			'uploadFiles' => array(new UploadedFile( TESTS . '/TestFiles/Home-Network.pdf', 0, UPLOAD_ERR_OK, 'Home-Network.pdf', 'application/pdf')),
		);
		$this->post( 'documents/add', $data );
		$this->assertFlashMessage( 'The document could be saved successfully', 'flash' );
}

public function testAddAuthorizedPostDataOKActiveFalse(): void {
		$data = array(
			'active' => false,
			'uploadFiles' => array(new UploadedFile( TESTS . '/TestFiles/Home-Network.pdf', 0, UPLOAD_ERR_OK, 'Home-Network.pdf', 'application/pdf')),
		);
		$this->post( 'documents/add', $data );
		$this->assertFlashMessage( 'The document could be saved successfully', 'flash' );
}

Denormalization between URI query-string and ServerRequest query-params

Today, I was bitten by the denormalization of URI query-strings between the URI model and the ServerRequest model.

I was delegating a request object, and although the URI included a set of query params, these did not propagate from the URI model to the ServerRequest model - and the consumer component happened to be getting this information from the ServerRequest model rather than from the URI model, and so of course this turned into somewhat of a nightmare of debugging and tracing.

Per the relevant doc-block PSR-7, this denormalization may be expected:

Note: the query params might not be in sync with the URI or server
params. If you need to ensure you are only getting the original
values, you may need to parse the query string from getUri()->getQuery()
or from the QUERY_STRING server param.

Note the precise phrasing: it might not be in sync with the URI model.

IMO, it's extremely problematic that PSR-7 was designed with a built-in denormalization issue, and since the specification seems to imply that implementations might (may) keep these values in sync, I strongly suggest we do that.

Now, I understand that these two models are, strictly speaking, incompatible - because the query string is just a string, and doesn't have to follow the common a=1&b=2 query format, and as such, you can't simply make this data synchronize in both directions.

However, this is still denormalization, and it still causes problems - having to update both values with two representations of the same data basically guarantees inconsistency, which basically guarantees (eventually) bugs.

Since the query string is the most general representation of the query data, I'd suggest treating the query-params in the ServerRequest as an accessor for the query-string inside the URI model.

You can of course still denormalize the query data internally (for performance) but it should behave as though the query-string is one value.

The elephant in the room of course is this: what happens if I ask the ServerRequest model for the query params, and the query-string in the underlying URI model isn't something that can be decoded as query params?

I suspect this question is what lead to apparent overthinking in the design of PSR-7, and I think that one possible answer to that question is actually much simpler than you may be thinking. The answer lies in PHP itself. What does PHP do if you provide a query-string it can't decode? Simple answer: nothing.

While this may seem "wrong" on the surface, it's actually completely appropriate - the $_GET superglobal, just like the ServerRequest::getQueryParams() method I'm proposing, provides an API that lets you access correctly encoded query parameters extracted from the query string, only if such paramters are present.

If you think of it that way, if there is an underlying query string in the URI model that doesn't contain such encoded parameters, that's precisely what you'd expect to be able to access: an empty array. If you wanted (or wanted to manipulate) the actual query-string, you'd ask the URI model for that.

I don't believe there's any real disconnect there at all; and it's consistent with PHP's own behavior, and therefore shouldn't really be surprising at all.

As things stand, the model doesn't actually make any sense - what we're dealing with is two representations of the same value, not two different values. The way it's modeled right now, the model actually permits the same property to have two different values at the same time.

I'm sure that makes a bunch of sense to people who understand quantum mechanics, but that's probably not most of us ;-)

The bottom line is that these are two different representations of the query string portion of the request URI, not two different values.

Would you be open to changing this?


Originally posted by @mindplay-dk at zendframework/zend-diactoros#184

Huge memory usage, despite using SapiStreamEmitter

Huge memory usage, despite using SapiStreamEmitter

When using Zend\Diactoros\Server with ->setEmitter(new \Zend\Diactoros\Response\SapiStreamEmitter());, it is still huge memory usage.

here is reproduce code.

<?php
use Zend\Diactoros\Server;
// zendframework/zend-diactoros version is 1.3.10
require_once __DIR__.'/vendor/autoload.php';
$server = Server::createServer(function () {
    // create empty 10MB file
    // $ dd if=/dev/zero of=tempfile bs=1M count=10
    return new \Zend\Diactoros\Response(fopen('tempfile', 'r'));
}, $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES);
$server->setEmitter(new \Zend\Diactoros\Response\SapiStreamEmitter());
$server->listen();
// for builtin server
file_put_contents("php://stdout", "\nMemory Usage: " . formatBytes(memory_get_peak_usage(true)));

function formatBytes($bytes, $precision = 2) {
    if ( abs($bytes) < 1024 ) $precision = 0;
    $sign = '';
    if ( $bytes < 0 ) {
        $sign = '-';
        $bytes = abs($bytes);
    }
    $exp   = floor(log($bytes) / log(1024));
    $bytes = sprintf('%.'.$precision.'f', ($bytes / pow(1024, floor($exp))));
    return $sign . $bytes .' '. ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'][$exp];
}

expected Memory Usage is 2.00 MB,
but showned Memory Usage is 16.00 MB.

I think that reason is Server::listen() calls ob_start,
but did not clean output buffer (ob_end_clean)


Originally posted by @sasezaki at zendframework/zend-diactoros#232

Request HTTP method defaults to empty string

Discovered while digging in php-http/curl-client#14

Apparently, diactoros defaults the HTTP method when building a new Request('http://example.com') to '' (empty string). As far as I know, an empty string is not a valid HTTP method (not sure if that assumption is reflected in the HTTP spec), and therefore the initial state of a diactoros HTTP request is invalid, and should lead to an exception.


Originally posted by @Ocramius at zendframework/zend-diactoros#150

CallbackStream and Server Sent Event (SSE) ?

Hi,

Do you know how we can play with SSE ?
I'm trying to use CallbackStream to handle my SSE manager with code like this one:

$stream = new CallbackStream( function () use ( $that ) {
      $that->setStart( time() );
      echo 'retry: ' . ( $that->client_reconnect * 1000 ) . "\n";	// Set the retry interval for the client
      while ( true ) {
        // Leave the loop if there are no more handlers
        if ( !$that->hasEventListener() ) {
          break;
        }
        if ( $that->isTick() ) {
          // No updates needed, send a comment to keep the connection alive.
          // From https://developer.mozilla.org/en-US/docs/Server-sent_events/Using_server-sent_events
          echo ': ' . sha1( mt_rand() ) . "\n\n";
        }

        // Start to check for updates
        foreach ( $that->getEventListeners() as $event => $handler ) {
          if ( $handler->check() ) { // Check if the data is avaliable
            $data = $handler->update(); // Get the data
            $id = $that->getNewId();
            $that->sendBlock( $id, $data, $event );

            // Make sure the data has been sent to the client
            $that->flush();
          }
        }
        // Break if the time exceed the limit
        if ( $that->exec_limit !== 0 && $that->getUptime() > $that->exec_limit ) {
          break;
        }
        // Sleep
        $that->sleep();
      }
    } );

    $response = new Response();
    $response->withHeader( 'Content-Type', 'text/event-stream' )
             ->withHeader( 'Cache-Control', 'no-cache' )
             ->withHeader( 'X-Accel-Buffering', 'no' );

    if ( $this->allow_cors ) {
      $response->withHeader( 'Access-Control-Allow-Origin', '*' );
      $response->withHeader( 'Access-Control-Allow-Credentials', 'true' );
    }

    if( $this->use_chunked_encoding ) {
      $response->withHeader( 'Transfer-encoding', 'chunked' );
    }

    return $response->withStatus( 200 )->withBody( $stream );

How can I use echo and flush behavior with CallbackStream ?

Regards,


Originally posted by @Wikiki at zendframework/zend-diactoros#229

Psalm integration

Feature Request

Q A
QA yes

Summary

As decided during the Technical-Steering-Committee Meeting on August 3rd, 2020, Laminas wants to implement vimeo/psalm in all packages.

Implementing psalm is quite easy.

Required

  • Create a .psalm.xml.dist in the project root
  • Copy and paste the contents from this psalm.xml.dist
  • Run $ composer require vimeo/psalm
  • Run $ vendor/bin/psalm --set-baseline=psalm-baseline.xml
  • Add a composer script static-analysis with the command psalm --shepherd --stats
  • Add a new line to script: in .travis.yml: - if [[ $TEST_COVERAGE == 'true' ]]; then composer static-analysis ; fi
  • Remove phpstan from the project (phpstan.neon.dist, .travis.yml entry, composer.json require-dev and scripts)
Optional
  • Fix as many psalm errors as possible.

`UploadedFile::moveTo()` doesn't remove the original file when used in CLI context and keep grab the handle.

Bug Report

Q A
Version(s) 2.11.2

Summary

UploadedFile::moveTo() doesn't remove the original file when used in CLI context and keep grab the handle. So PHPUnit can't remove setup files. It fixed in this PR.
#98

Current behavior

The uploaded file could not be removed when we called UploadedFile::moveTo().

How to reproduce

Instantiate UploadedFile, and post the object in PHPUnit testing, then remove it at tearDown, it could not be remove and raise error 'the file is in busy'.

Expected behavior

If UploadedFile::moveTo was called, the original file must be moved.

PhpInputStream's getSize function is Wrong!

reference: https://www.php.net/manual/en/wrappers.php.php
php://input is not support fstat

Supports stat() php://memory and php://temp only.
  • I was not able to find an open or closed issue matching what I'm seeing.
  • This is not a question. (Questions should be asked on chat (Signup here) or our forums.)

Provide a narrative description of what you are trying to accomplish.

Code to reproduce the issue

Expected results

Actual results


Originally posted by @zhushengwen at zendframework/zend-diactoros#380

Stream is not fully compatible with GD resource

Bug Report

Q A
Version(s) 2.4.0

Summary

Using a GD resource works fine until there is interaction with the stream.

Current behavior

When working with GD Images, most of the methods of the Stream (with PHP 8.0 its GDImage) will result in errors.

How to reproduce

    public function testIsReableWithGdResource()
    {
        $resource = imagecreate(1, 1);
        $stream   = new Stream($resource);
        $this->assertTrue($stream->isReadable());
    }

    public function testCloseWithGdResource()
    {
        $resource = imagecreate(1, 1);
        $stream   = new Stream($resource);
        $this->assertNull($stream->close());
    }

result in

1) LaminasTest\Diactoros\StreamTest::testIsReableWithGdResource
stream_get_meta_data(): supplied resource is not a valid stream resource

2) LaminasTest\Diactoros\StreamTest::testCloseWithGdResource
fclose(): supplied resource is not a valid stream resource

So the existing code is already broken and doesn't work with image resources.

Expected behavior

Using methods return proper informations such as the GD Image/Resource is not writable, seekable, e.g.

Originally posted by @ADmad in #46 (comment)

Add DownloadResponse Class

Why is the new feature needed? What purpose does it serve?

After doing a bit of searching, I didn't find a class that would send a CSV response. There were the Text, JSON, HTML, Redirect, XML, and Empty response classes, but nothing specific to CSV. So I created this PR to add a CSV response class, which can send both plain CSV text as well as a response that will be interpreted by the client as a downloadable file.

How will users use the new feature?

Users can use the CSV response class very similarly to how they use the existing response classes. The only difference is that if they supply a file name as the third parameter to the constructor, then a download response will be sent, not a textual response.


Originally posted by @settermjd at zendframework/zend-diactoros#361

Multipart Stream Factory

Feature Request

Q A
New Feature yes
RFC kinda
BC Break no

Summary

I've seen there was already such a feature request in #48 which was somehow related to PSR-7 Streams which do actually represent a multipart payload.

From what I can see, php-http/multipart-stream-builder is the only library which does actually provide this functionality but I wonder if this should also be possible via diactoros itself.

Something like this came to my mind:

interface MultipartStreamInterface extends StreamInterface
{
    /** @return non-empty-string */
    public function getBoundary(): string;
}

interface PartOfMultipartStreamInterface
{
     /**
       * Returns the filename of the multipart stream.
       * In case no filename was provided, this method returns an empty string.
       */
     public function getFilename(): string;

     /**
      * Returns all headers which are passed for the stream.
      * All header names are converted to lowercase.
      * @return array<non-empty-string,non-empty-string>
      */
     public function getHeaders(): array;

     public function getStream(): StreamInterface;
}

interface MultipartStreamFactoryInterface extends StreamFactoryInterface
{
    /** @param non-empty-string $boundary */
    public function createMultipartStream(string $boundary, PartOfMultipartStreamInterface ...$parts): MultipartStreamInterface;

    /**
      * @param array<non-empty-string,non-empty-string> $headers
      */
    public function createPartOfMultipart(StreamInterface $stream, string $name, string $filename = '', array $headers = []): PartOfMultipartStreamInterface;
}

I guess this API should provide anything we need to generate multipart streams, right?
Happy to get some feedback here.

Empty header check breaking change

The following commit causes breaking issues and probably should not have been implemented in a minor version.

zendframework/zend-diactoros@ee4bcdc#diff-5abca4d9d5693da46d10a54795b1192d

Specifically this change breaks laravel/passport ^3.0 which depends on ~1.0 of this library.

I've opened a ticket for them to patch branch 3.x, but that patch may introduce new problems. That's why I'd suggest this update be reverted from 1.x of the zend framework.


Originally posted by @soundsgoodsofar at zendframework/zend-diactoros#356

Relative stream possible issue with pointers

I was looking through stream implementation. Relative stream and the stream it wraps are sharing same pointer, right?
So if we rewind wrapped stream, read on relative will return data before offset position.
Also tell() will give negative position, which is out of bounds error.

This shared pointer in streams looks extremely bug prone to me.

May be on seekable streams we should store pointer locally, set it before performing operation and record new position after doing it?

As simplified example:

public function read()
{
    $this->seek($this->position, SEEK_SET);
    $result = fread($resource, $length);
    $this->position = $this->tell();
    return $result;
}

Originally posted by @Xerkus at zendframework/zend-diactoros#147

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Awaiting Schedule

These updates are awaiting their schedule. Click on a checkbox to get an update now.

  • Lock file maintenance

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

composer
composer.json
  • php ~8.1.0 || ~8.2.0 || ~8.3.0
  • psr/http-factory ^1.0.2
  • psr/http-message ^1.1 || ^2.0
  • http-interop/http-factory-tests ^0.9.0
  • laminas/laminas-coding-standard ~2.5.0
  • php-http/psr7-integration-tests ^1.3
  • phpunit/phpunit ^9.6.16
  • psalm/plugin-phpunit ^0.19.0
  • vimeo/psalm ^5.22.1
github-actions
.github/workflows/continuous-integration.yml
.github/workflows/docs-build.yml
.github/workflows/release-on-milestone-closed.yml

  • Check this box to trigger a request for Renovate to run again on this repository

trailer headers for stream responses

My php service generates a very big list of items.
I decided to stream items on the fly as they are generated to save memory.
I implemented response body as a custom stream that wraps a generator which yields items.

Now I need to append a checksum trailer header to that stream response, so clients can check response validity.

What is a proper way of appending trailer header to a stream response in diactoros?


Originally posted by @drscre at zendframework/zend-diactoros#231

getQueryParams not returning proper data type

Bug Report

zend-expressive v2.0.2

Summary

Do not know if this is a known issue or if this has already been fixed. The issue exists in zend-expressive v2.0.2. When accessing url query parameters via $request->getQueryParams(), integer values will be cast to string (e.g. 2 => "2"). I discovered this on parsing a query string encoded with http_build_query on an array.

Same thing happens when applying parse_str($_SERVER['QUERY_STRING']).

Current behavior

$request->getQueryParams() casts integers to strings

How to reproduce

$aggregates = [
            'aggregates' => [
                'number' => 1
            ]
        ];
  • $client->request('GET', $myServiceUrl . '?' . http_build_query($aggregates))
  • Sends sth. like [myServiceUrl]?aggregates%5Bnumber%5D=1 to your service
  • $params = $request->getQueryParams();
  • var_dump($params['aggregates']) // number: "1"

Expected behavior

1 stays 1 😎

FYI @heiglandreas

Uri::__toString adds extra delimiters

I'm finishing coding League\Url v4 and it exposed the following class in public API

Url::sameValueAs(Psr\Http\Message\UriInterface $url); 

To compare two PSR-7 UriInterface object based on their __toString method output.

I tried to make it work with Diactoros but I failed with the following edge cases URLs:

  • http:/example.com
  • http:example.com

In both cases the object is instantiated and the respective Uri components are correctly set but the __toString method adds extra path and/or authority delimiters.

Below the code to reproduce the bugs:

use Zend\Diactoros\Uri;
$url = new Uri('http:/example.com');
echo $url->__toString(); //expected http:/example.com but got http:///example.com
new Uri($url->__toString()); //throw InvalidArgumentException

The authority delimiters are added (not required according to PSR-7) and the method returns an invalid Uri.

use Zend\Diactoros\Uri;
$url = new Uri('http:example.com');
echo $url->__toString(); //expected http:example.com but got http:///example.com
new Uri($url->__toString()); //throw InvalidArgumentException

The authority delimiters and a path delimiter are added (not required according to PSR-7) and the method returns an invalid Uri.


Originally posted by @nyamsprod at zendframework/zend-diactoros#65

`FilterUsingXForwardedHeaders` should correctly deal with `<host>:<port>` pair in `X-FORWARDED-HOST` header

Hello contributors!

I get from my web-server headers like:

X-FORWARDED-HOST = host:port 
X-FORWARDED-PORT = port

I am using FilterUsingXForwardedHeaders filter and in result I get wierd URI from ServerRequestFactory::fromGlobals with port duplicated like https://host:port:port/path.

I guessX-FORWARDED-HOST in FilterUsingXForwardedHeaders should be parsed in the same way like ServerRequestFactory::marshalHostAndPortFromHeader() did.

In earlier versions (updated 2.9.2 -> 2.13.0) it was working fine. So it's a kind of little BC Break too :)

I understand that I can implement FilterServerRequestInterface myself, but it would be more convenient to have such feature out of the box.

Thank you!

Zend Framework Bridge is a required dependency

Bug Report

Q A
Version(s) 2.x

Summary

The Diactoros package currently forces installation of the Zend Framework bridge package, laminas/laminas-zendframework-bridge. For projects that can switch over easily, this is a completely unnecessary dependency.

Unless I'm missing something crucial here, I would instead recommend placing this dependency in the suggest configuration of the composer.json for this library.

Current behavior

Installing laminas/laminas-diactoros via Composer forces the installation of laminas/laminas-zendframework-bridge.

How to reproduce

composer require laminas/laminas-diactoros

Both the Diactoros library and the Zend Framework bridge are installed by Composer.

Expected behavior

Only the Diactoros library is installed by Composer.

Psr7\MultipartStream compatible

Feature Request

upload a image from web -> To Server A
A:
$request->ServerRequestFactory::createGlobal();
use GuzzleHttp to send this request ,  -> To Server B;

B: 
accept $_FILE is empty
Q A
New Feature yes
RFC yes/no
BC Break yes/no

Summary

  • guzzle\GuzzleHttp ->applyOptions line:473
      
        if ($request->getBody() instanceof Psr7\MultipartStream) {
            $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
            $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
                . $request->getBody()->getBoundary();
        }

Generators are not supported for JSON responses.

Code to reproduce the issue

function getSomeData(): Generator {
    yield 1 => 'One';
    yield 2 => 'Two';
    yield 3 => 'Three';
}

$data = getSomeData();
$json = new Zend\Diactoros\Response\JsonResponse($data);

Expected results

Response should consume the generator and treat it as if a normal PHP array was passed in:

$data = [
    1 => 'One',
    2 => 'Two',
    3 => 'Three'
];

$json = new Zend\Diactoros\Response\JsonResponse($data);

Actual results

An error is thrown instead: "Trying to clone an uncloneable object of class Generator..."


Originally posted by @nbish11 at zendframework/zend-diactoros#365

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.