Giter Site home page Giter Site logo

slim-psr7's People

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

slim-psr7's Issues

Non droppable cache

I have noticed when we call the detach method of a stream the cache property stay attached to some resource. Accroding to Psr7/StreamInterface a stream is unusable after that. Maybe, it makes sense to assign the cache property to null.

PHPUnit error

I just cloned the repository, run composer install and then tried phpunit. I got the following error and was wondering, if that is only in my environment?

1) Slim\Tests\Psr7\Integration\ServerRequestTest::testGetUploadedFiles
RuntimeException: Could not create Stream. Check your config

...\vendor\php-http\psr7-integration-tests\src\BaseTest.php:111
...\vendor\php-http\psr7-integration-tests\src\ServerRequestIntegrationTest.php:83

Converting a non seekable stream to a string

I looked at the source code of various Stream class implementations. In particular, the __toString method.

I noticed inconsistent behavior when working with non-seekable resources. For instance, a simple pipe - popen('echo 12', 'r').

$fd = popen('echo 12', 'r');
$stream = new Stream($fd);
(string) $stream; // implementation dependent

zend-diactoros && nyholm/psr7
They try to rewind a pipe according to standart, but ignore seek operation and return content, because a pipe is non-seekable.
guzzlehttp/psr7 && slim/psr7
They try to rewind a stream then as result get RuntimeException and return the empty string.
In my opinion, it will be more logical to use the first strategy. What do you thing about it?

Error occurs when cast request body to string in PHP 7.4

Status code is 200 on Docker. But POST JSON by Postman return 500.

Trying to access array offset on value of type bool on line 389 in vendor/slim/psr7/src/Stream.php

class PostAction extends Action
{
    protected function action(): Response
    {
        $this->logger->debug('debug', [(string)$this->request->getBody()]);
        return $this->response;
    }
}

request->getHeaders() returns HTTP_ uppercased header names

Given the following slim route:

    // Echo back the request been sent to us
    $app->any('/check/request', function (Request $request, Response $response, array $args) use ($logger) {
        $request->getBody()->rewind();

        $payload = [
            'method'           => $request->getMethod(),
            'body'             => $request->getBody()->getContents(),
            'headers'          => $request->getHeaders(),
            'uri_path'         => $request->getUri()->getPath(),
            'query_parameters' => $request->getQueryParams(),
        ];

        return $response
            ->withHeader('content-type', 'application/json')
            ->withStatus(200)
            ->withBody(stream_for(json_encode($payload)));
    });

And the following curl request:

curl "localhost:8080/check/request?foo=bar" -XPUT -H"cov: fefe" -d"lalala"

The following comes out as a response:

{
    "method": "PUT",
    "body": "lalala",
    "headers": {
        "HTTP_HOST": [
            "localhost:8080"
        ],
        "HTTP_USER_AGENT": [
            "curl\/7.64.0"
        ],
        "HTTP_ACCEPT": [
            "*\/*"
        ],
        "HTTP_COV": [
            "fefe"
        ]
    },
    "uri_path": "\/check\/request",
    "query_parameters": {
        "foo": "bar"
    }
}

As you can see, the cov header comes out as HTTP_COV.

Slim 3.12.1

HTTP POST parameters not detected when using jQuery $.ajax

Context
Currently, HTTP POST request parameters are detected when the ContentType of the HTTP Request equals either application/x-www-form-urlencoded or multipart/form-data. After this "detection", they can be access using $request->getParsedBody().

When using jQuery $.ajax to dispatch an HTTP POST request, the default ContentType of the HTTP Request is application/x-www-form-urlencoded; charset=UTF-8, which is valid syntax for this header.

Problem
When using jQuery $.ajax to dispatch an HTTP POST request, the current approach does not properly detect this as being a HTTP POST request and $request->getParsedBody() remains empty, while $request->getBody() contains content like parameter1=value1&parameter2=value2&parameterN=valueN.

Workaround
Currently the following workarounds can be considered:

  • use ZendExpressive Body Parsing Middleware which does properly detect the HTTP POST request when the ContentType is application/x-www-form-urlencoded; charset=UTF-8, but this requires the complete set of Zend-Expressive Middleware helpers to be installed.
  • explicitly set the $.ajax ContentType to application/x-www-form-urlencoded

Possible solution
Maybe the current exact match for application/x-www-form-urlencoded can be loosened a bit? At least this is how the FormUrlEncodedStrategy of the BodyParsingMiddleware does it

A more robust / future proof approach might be to adopt a similar "strategy" mechanism as the BodyParsingMiddleware, which also has a strategy for detecting JSON payloads, also see https://github.com/zendframework/zend-expressive-helpers/tree/master/src/BodyParams

BasePath processing is missing

According to the documentation

The PSR-7 Request object’s URI is itself an object that provides the following methods to inspect the HTTP request’s URL parts:

getScheme()
getAuthority()
getUserInfo()
getHost()
getPort()
getPath()
getBasePath()
getQuery() (returns the full query string, e.g. a=1&b=2)
getFragment()
getBaseUrl()
You can get the query parameters as an associative array on the Request object using getQueryParams().

Base Path
If your Slim application's front-controller lives in a physical subdirectory beneath your document root directory, you can fetch the HTTP request's physical base path (relative to the document root) with the Uri object's getBasePath() method. This will be an empty string if the Slim application is installed in the document root's top-most directory.

Slim v3 implemented the basePath processing as per https://github.com/slimphp/Slim/blob/3.x/Slim/Http/Uri.php#L204

Validation is processed twice

$msg = new Message();
$msg->withHeader("name", "value");
[calls]
Message::withHeader($name, $string) [Message.php]
  Headers::validateHeaderName($name);
  Headers::validateHeaderValue($value);
  ...
  $clone->headers->setHeader($name, $value)
    Headers::setHeader($name, $value) [Headers.php]
       $values = $this->validateAndTrimHeader($name, $values);
       ...
       Headers::validateHeaderName($name);
       Headers::validateHeaderValue($value);
       ...

The same is true for the withAddedHeader method. I don't know how to redesign the code to create pull request.

GetHeaderLine() concatenates with a comma only

Not sure whether that is an issue. But the example in the PSR7 specification has not only a comma as separator in a multivalue header, but also a white-space.

Quote from https://www.php-fig.org/psr/psr-7/

$header = $message->getHeaderLine('foo');
// $header contains: 'bar, baz'

In a quick test I have recognized, that other implementations (Nyholm, Guzzle) do this as written in the example.

What is the expected value? With or without white-space after the comma?

Request body is seekable but size is null when a file is sent

Hello there, I'm using Slim 4.5.0.
I'm PUTting a binary file to one of my routes but the Slim\Psr7\Stream instance I get from the Slim\Http\ServerRequest object won't tell me the content size. I'm NOT sending a multipart/form-data request. I'm just PUTting a file with curl -T "filename" "http://my-host/my-route"

Here's my PHP code. $request->getBody()->getSize() is null even though the stream is reported seekable and the Content-Length header was provided.

public function putMediaContent(ServerRequestInterface $request, ResponseInterface $response, array $args) : ResponseInterface {
    //body is a Slim\Psr7\Stream instance
    $body = $request->getBody();
    //size is null
    $size = $body->getSize();
    //isSeekable is true
    $isSeekable = $body->isSeekable();
    //contentLength has the correct uploaded file size
    $contentLength = $request->getHeaders()['Content-Length'][0];

    //...
}

This is a problem since I then have to pass this stream to an S3Client for cloud upload and it complains about the fact the size is unknown.
Is this intended?

Thanks.

Parsing body (form post) without data throws error - PHP 7.4

You can reproduce the error, by enabling the BodyParsingMiddleware and submit a post form without named input fields.

I used Slim 4, all latest packages and PHP 7.4.

Error message

Details
Type: ErrorException
Code: 0
Message: Trying to access array offset on value of type bool
File: \path\to\project\vendor\slim\psr7\src\Stream.php
Line: 351
Trace

#0 C:\dev\Projekte\Tasky\vendor\slim\psr7\src\Stream.php(351): {closure}(8, 'Trying to acces...', '\path\to\project...', 351, Array)
#1 C:\dev\Projekte\Tasky\vendor\slim\psr7\src\Stream.php(256): Slim\Psr7\Stream->isPipe()
#2 C:\dev\Projekte\Tasky\vendor\slim\psr7\src\Stream.php(278): Slim\Psr7\Stream->isSeekable()
#3 C:\dev\Projekte\Tasky\vendor\slim\psr7\src\Stream.php(141): Slim\Psr7\Stream->rewind()
#4 C:\dev\Projekte\Tasky\vendor\slim\slim\Slim\Middleware\BodyParsingMiddleware.php(161): Slim\Psr7\Stream->__toString()
#5 C:\dev\Projekte\Tasky\vendor\slim\slim\Slim\Middleware\BodyParsingMiddleware.php(62): Slim\Middleware\BodyParsingMiddleware->parseBody(Object(Slim\Psr7\Request))
#6 C:\dev\Projekte\Tasky\vendor\slim\slim\Slim\MiddlewareDispatcher.php(140): Slim\Middleware\BodyParsingMiddleware->process(Object(Slim\Psr7\Request), Object(class@anonymous))
#7 C:\dev\Projekte\Tasky\vendor\slim\slim\Slim\Middleware\RoutingMiddleware.php(60): class@anonymous->handle(Object(Slim\Psr7\Request))
#8 C:\dev\Projekte\Tasky\vendor\slim\slim\Slim\MiddlewareDispatcher.php(140): Slim\Middleware\RoutingMiddleware->process(Object(Slim\Psr7\Request), Object(class@anonymous))
#9 C:\dev\Projekte\Tasky\vendor\slim\slim\Slim\Middleware\ErrorMiddleware.php(107): class@anonymous->handle(Object(Slim\Psr7\Request))
#10 C:\dev\Projekte\Tasky\vendor\slim\slim\Slim\MiddlewareDispatcher.php(140): Slim\Middleware\ErrorMiddleware->process(Object(Slim\Psr7\Request), Object(class@anonymous))
#11 C:\dev\Projekte\Tasky\vendor\slim\slim\Slim\MiddlewareDispatcher.php(81): class@anonymous->handle(Object(Slim\Psr7\Request))
#12 C:\dev\Projekte\Tasky\vendor\slim\slim\Slim\App.php(215): Slim\MiddlewareDispatcher->handle(Object(Slim\Psr7\Request))
#13 C:\dev\Projekte\Tasky\vendor\slim\slim\Slim\App.php(199): Slim\App->handle(Object(Slim\Psr7\Request))
#14 C:\dev\Projekte\Tasky\public\index.php(86): Slim\App->run(Object(Slim\Psr7\Request))
#15 {main}

ParsedBody

I'm removing non-PSR-7 methods from Slim-Psr7

However, when it comes to the parsed body of the Request object, Should Slim-Psr7 continue to handle it's own decoding of body using the media types or should this functionality be moved elsewhere?

Component name

We can't use Slim\Http as we need that for Slim itself.

Options:

  1. Slim\Psr7
  2. Slim\HttpMessage

Response::withSomething returns instance of Message instead of Response

When calling a "with" method on a Response (and also Request) object, the returned type is not Response (or Request) but rather Message.

    public function home(Request $request, Response $response, array $args){   
        //Type of $response is Response (Slim\Psr7\Response)
        $response= $response->withHeader("test", "value");
        //Type of $response is now Message (Slim\Psr7\Message)  
        ....     
    }

This is not an issue until you need to use Response (or Request) methods that are not common to the Message object.

Cheers,
Noah

Add body parsing functionality in Request object

Currently we do not parse any incoming data in the Request object. All that functionality has been moved to the Slim-Http decorators repository.

We should by default at least support the incoming form data in the $_POST object and JSON.

Fallback for getallheaders() missing

Slim-Psr7 does only show the Host header on systems where getallheaders() is missing. My setup is Apache + PHP 7.2 via FPM. But I think there are many other cases, for example using nginx.
Slim3 has a fallback to parse the headers from environment in this case. And so do other PSR7 implementations like Nyholm/PSR7: https://github.com/Nyholm/psr7-server/blob/0.3.0/src/ServerRequestCreator.php#L52

Slim 3 example

composer require slim/slim
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\App;

require 'vendor/autoload.php';

$app = new App();

$app->get('/', function (Request $request, Response $response, array $args) {
    var_dump($request->getHeaders());
    return $response;
});

$app->run();

Result:

array(10) {
  ["HTTP_UPGRADE_INSECURE_REQUESTS"]=>(...)
  ["HTTP_DNT"]=>(...)
  ["HTTP_ACCEPT_ENCODING"]=>(...)
  ["HTTP_ACCEPT_LANGUAGE"]=>(...)
  ["HTTP_ACCEPT"]=>(...)
  ["HTTP_USER_AGENT"]=>(...)
  ["HTTP_CONNECTION"]=>(...)
  ["HTTP_X_ACCEL_INTERNAL"]=>(...)
  ["HTTP_X_REAL_IP"]=>(...)
  ["HTTP_HOST"]=>(...)
}

Slim 4 example

composer require slim/slim:4.0.0-beta
composer require slim/psr7
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;

require 'vendor/autoload.php';

$app = AppFactory::create();

$app->get('/', function (Request $request, Response $response, array $args) {
    var_dump($request->getHeaders());
    return $response;
});

$app->run();

Result:

array(1) {
  ["Host"]=>(...)
}

Response headers include received Authorization header

The Response constructor will by default create a Headers object to collect headers to be sent. The Headers constructor will call setHeaders() which will call parseAuthorizationHeader(). parseAuthorizationHeader() will try to create an Authorization header from data found in $_SERVER.

The result of this is that the Response headers include a copy of the Authorization header received in the request being processed.

The code comment for parseAuthorizationHeader() reads: "Parse incoming headers and determine Authorization header from original headers". My interpretation is that this code was never intended to be used for a Response.

withJson method is missing from Response class

I am trying to upgrade Slim framework used in my project from version 3 to version 4 and during the process I suddenly found out that withJson method has gone from the Response class. I want to understand why it is gone? I understand that Response class implements PSR-7 ResponseInterface, where withJson method is not included. But I don't think implementing ResponseInterface forbids Response class having some helper methods which will be very helpful.

Reuse base class code

The abstract class Message, among others, defines two protected properties - $headers & $body. Any derived class will be inherit them. In paticular, two classes Request & Response. But classes define constructor parameters differently.

  • Request::__construct(..., HeadersInterface $headers, StreamInterface $body)
  • Response::__construct(..., ?HeadersInterface $headers, ?StreamInterface $body)
    If the base class (Message) defines the constructor, what would be the default behavior ?
    ?HeadersInterface or HeadersInterface & ?StreamInterface or StreamInterface.

Missing docblocks

The class Cookies does not extend nor implement anything. But there are some docblocks like the following

/**
* {@inheritdoc}
*/
public function get(string $name, $default = null)

Where do they inherit from?

UriFactory doesn't set path correctly

Given a REQUEST_URI of /baz?foo=bar, the path in the Uri should be /baz, not /baz?foo=bar.

This is because in UriFactory::createFromGlobals(), we do:

$requestUri = $env->get('REQUEST_URI');

In Slim 3 we do:

$requestUri = parse_url('http://example.com' . $env->get('REQUEST_URI'), PHP_URL_PATH);

Nyholm does:

$uri = $uri->withPath(\current(\explode('?', $server['REQUEST_URI'])));

PHPUnit problems with getallheaders()

In #70 the file tests/Assets/PhpGetAllHeaders.php had been removed. This breaks PHPUnit on my system (Win10, PHP 7.1), because the following condition

if (function_exists('getallheaders')) {

always returns false (even if the function is defined in the Slim\Psr7 namespace via the file tests/Assets/PhpFunctionOverrides.php).

Test Output

There were 4 failures:

1) Slim\Tests\Psr7\Factory\ServerRequestFactoryTest::testCreateFromGlobals
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'application/json'
+''

D:\GitHub\Slim-Psr7\tests\Factory\ServerRequestFactoryTest.php:82

2) Slim\Tests\Psr7\Factory\ServerRequestFactoryTest::testCreateFromGlobalsWithParsedBody
null does not match expected type "array".

D:\GitHub\Slim-Psr7\tests\Factory\ServerRequestFactoryTest.php:110

3) Slim\Tests\Psr7\Factory\ServerRequestFactoryTest::testCreateFromGlobalsParsesBodyWithFragmentedContentType
null does not match expected type "array".

D:\GitHub\Slim-Psr7\tests\Factory\ServerRequestFactoryTest.php:172

4) Slim\Tests\Psr7\HeadersTest::testCreateFromGlobals
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
 Array (
-    'accept' => Array (...)
 )

D:\GitHub\Slim-Psr7\tests\HeadersTest.php:27

It seems that only failures 1 and 4 are directly connected, as the other failures remain even if I add the function getallheaders() to the root namespace.

Any reason for root-namespaced php built-in functions?

In \Slim\Psr7\NonBufferedBody::write() there are four function calls to php built-in functions. All of them are root-namespaced.

  • ob_get_level
  • ob_get_clean
  • flush
  • strlen

Is there any reason for that?

while (0 < \ob_get_level()) {
$buffered = \ob_get_clean() . $buffered;
}
echo $buffered . $string;
\flush();
return \strlen($string) + \strlen($buffered);

"Trying to access array offset on value of type bool" in isPipe()

Running 4.5.0, I'm consistently getting the following error w/ PHP 7.4.5:

Notice: Trying to access array offset on value of type bool in .../vendor/slim/psr7/src/Stream.php on line 389

The request seems to work, but I get Notice output in the result, ahead of my JSON body.

( ! ) Notice: Trying to access array offset on value of type bool in .../vendor/slim/psr7/src/Stream.php on line 389
--


1 | 0.0072 | 361776 | {main}( ) | .../index.php:0
2 | 0.0714 | 467296 | Slim\App->run( ??? ) | .../index.php:30
3 | 3.7541 | 564504 | Slim\App->handle( ??? ) | .../App.php:199
4 | 3.7542 | 564504 | Slim\MiddlewareDispatcher->handle( ??? ) | .../App.php:215
5 | 3.7542 | 564504 | {anonymous-class:.../vendor/slim/slim/Slim/MiddlewareDispatcher.php:127-142}->handle( ??? ) | .../MiddlewareDispatcher.php:81
6 | 3.7542 | 564504 | Slim\Middleware\ErrorMiddleware->process( ???, ??? ) | .../MiddlewareDispatcher.php:140
7 | 3.7542 | 564504 | {anonymous-class:.../vendor/slim/slim/Slim/MiddlewareDispatcher.php:127-142}->handle( ??? ) | .../ErrorMiddleware.php:107
8 | 3.7542 | 564504 | Slim\Middleware\RoutingMiddleware->process( ???, ??? ) | .../MiddlewareDispatcher.php:140
9 | 3.7573 | 573144 | {anonymous-class:.../vendor/slim/slim/Slim/MiddlewareDispatcher.php:127-142}->handle( ??? ) | .../RoutingMiddleware.php:60
10 | 3.7573 | 573144 | Slim\Middleware\BodyParsingMiddleware->process( ???, ??? ) | .../MiddlewareDispatcher.php:140
11 | 3.7574 | 573144 | Slim\Middleware\BodyParsingMiddleware->parseBody( ??? ) | .../BodyParsingMiddleware.php:62
12 | 3.7574 | 573144 | Slim\Psr7\Stream->__toString( ) | .../BodyParsingMiddleware.php:161
13 | 3.7574 | 573144 | Slim\Psr7\Stream->rewind( ) | .../Stream.php:162
14 | 3.7574 | 573144 | Slim\Psr7\Stream->isSeekable( ) | .../Stream.php:299
15 | 3.7574 | 573144 | Slim\Psr7\Stream->isPipe( ) | .../Stream.php:277

{ ... my JSON response ... }

The line of code is:

$this->isPipe = (fstat($this->stream)['mode'] & self::FSTAT_MODE_S_IFIFO) !== 0;

I'm expecting that this error means $this->stream is a boolean, but in the debugger I never see this to be the case. It's reliably an object. The error appears to occur on the second call to isPipe().

Note that this all works when errors are disabled in production. It's just causing trouble in dev.

Cookie default-fallback is not working if value is `null`

Not sure it that is an issue, but the following test fails.

        $cookies = new Cookies(['expires' => null]);

        $this->assertFalse($cookies->get('not-set', false));
        $this->assertNull($cookies->get('expires', 'Wed, 26 Jan 2020 12:00:00 GMT'));

We pass expires to be null in the constructor. The method $cookies->get() would check if there is a value defined for the given name and if not, it returns the second given parameter (default-fallback). The first assert-line is working as expected, but the second one would not return null, which it should in my opinion.

This is because the method $cookies->get() uses isset to check the existence of an array key. This function returns false if the key does not exist or if the value is null. See

public function get(string $name, $default = null)
{
return isset($this->requestCookies[$name]) ? $this->requestCookies[$name] : $default;
}

Should we change that to array_key_exists?

Construction of a Uri object

How should we construct a Uri object?
Our current constructor is:

public function __construct($scheme, $host, $port = null, $path = '/', $query = '', $fragment = '', $user = '', $password = '')

Should it be changed?

I think that the most common use-case is that the user has a string representation of a URI (e.g. "http://example.com/foo") & currently we use a factory called createFromString for this case.

Should we update the way we create Uris for Slim 4? These are the choices for construction of a Uri:

  1. $uri = new Uri('http', 'example.com', '/foo'): (as current)
  2. $uri = new Uri("http://example.com/foo"): (constructor takes a string)
  3. $uri = Uri::createFromString("http://example.com.foo"): (static factory in Uri class)

Note that we also want to support the upcoming http-interop's factories (PSR-17), so we'll also have this way to create a Uri from a string:

$uri = UriFactory::createUri("http://example.com/foo");

Any preferences to how we should create Uris in addition to UriFactory::createUri() ?

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.