nyholm / psr7-server Goto Github PK
View Code? Open in Web Editor NEWHelper classes to use any PSR7 implementation as your main request and response
License: MIT License
Helper classes to use any PSR7 implementation as your main request and response
License: MIT License
Recently I was bringing up a site based on Grav, which uses psr7-server/ServerRequestCreator.php directly to prepare a request object for further manipulation. The server I was using had the following peculiarity: it had $_SERVER['REQUEST_SCHEME']
set to http
and at the same time $_SERVER['HTTPS']
set to on
. All of that while I was using exclusively HTTPS. This caused an occasional problem when a redirection was made to e.g. http://example.com:443/about
instead of https://example.com/about
. I believe the way the scheme detection works now is a problem, since current code will set scheme as http
even though the server also reports $_SERVER['HTTPS']
as being used. I mean this fragment:
psr7-server/src/ServerRequestCreator.php
Lines 272 to 276 in b846a68
Shouldn't HTTPS
header have precedence here? Something like this code here (from https://www.designcise.com/web/tutorial/how-to-check-for-https-request-in-php):
$isHttps =
$_SERVER['HTTPS']
?? $_SERVER['REQUEST_SCHEME']
?? $_SERVER['HTTP_X_FORWARDED_PROTO']
?? null
;
$isHttps =
$isHttps && (
strcasecmp('on', $isHttps) == 0
|| strcasecmp('https', $isHttps) == 0
)
;
or, at least, reverse the order of condition checks?
I think this problem is somewhat related, but not identical to #29.
Hi!
I am getting wrong URI when running on localhost with custom port:
<?php declare(strict_types = 1);
require __DIR__ . '/../vendor/autoload.php';
use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7Server\ServerRequestCreator;
$psr17Factory = new Psr17Factory();
$creator = new ServerRequestCreator(
$psr17Factory,
$psr17Factory,
$psr17Factory,
$psr17Factory
);
$request = $creator->fromGlobals();
echo $request->getUri()->__toString();
http://localhost:8000:8000/
The problem is probably due to mechanism used to create URI in ServerRequestCreator::createUriFromArray()
. URI host gets populated with $_SERVER['HTTP_HOST']
, but this contains also the port (see for example here: https://stackoverflow.com/a/12046836 ).
I propose two solutions:
$_SERVER['HTTP_HOST']
$_SERVER['SERVER_NAME']
instead - I am not sure about the consequencesI may create a pull request with fix if you want.
The following warning is occurred because trying to create a stream from an empty filename.
Warning: fopen(): Filename cannot be empty
The problem is in createUploadedFileFromSpec()
function.
I think that the function should check for upload errors.
private function createUploadedFileFromSpec(array $value)
{
if (\is_array($value['tmp_name'])) {
return $this->normalizeNestedFileSpec($value);
}
return $this->uploadedFileFactory->createUploadedFile(
$this->streamFactory->createStreamFromFile($value['tmp_name']),
(int) $value['size'],
(int) $value['error'],
$value['name'],
$value['type']
);
}
When creating a PSR request from globals, the hostname is set twice in the Host header. This is not allowed according to the RFC:
A server MUST respond with a 400 (Bad Request) status code to any
HTTP/1.1 request message that lacks a Host header field and to any
request message that contains more than one Host header field or a
Host header field with an invalid field-value.
The first hostname is added in the ServerRequest object constructor:
if (!$this->hasHeader('Host')) {
$this->updateHostFromUri();
}
However, Host header is added again in the ServerRequestCreator
class in the fromArrays()
function here because it uses the withAddedHeader
function:
foreach ($headers as $name => $value) {
// Because PHP automatically casts array keys set with numeric strings to integers, we have to make sure
// that numeric headers will not be sent along as integers, as withAddedHeader can only accept strings.
if (\is_int($name)) {
$name = (string) $name;
}
$serverRequest = $serverRequest->withAddedHeader($name, $value);
}
This results in the following Host header in the Psr request:
Host: hostname.tld, hostname.tld
Any particular reason why getHeadersFromServer
is part of ServerRequestCreatorInterface
?
It's not like you can call it as ServerRequestCreatorInterface::getHeadersFromServer()
- you always have to reference the implementation of a static method... static methods in interfaces don't generally make any sense - possibly except when you're just trying to make sure you implement a static method in the same way in several classes, but even then, it doesn't serve as any kind of abstraction, and you only have one implementation here, so...?
As documented in this issue, apache_request_headers()
/getallheaders()
isn’t guaranteed to return valid header data, even when the request made was valid. Specifically, in some server configurations, an Expect: 100-continue
header (sent by e.g. cURL when making large file upload requests) is removed by converting each character in the key and value to a space, rather than just ignoring the header.
I propose that ServerRequestCreator::fromGlobals()
should filter out the following invalid header data before creating a ServerRequestInterface
:
getallheaders()
where both the key and value consist entirely of whitespace$_SERVER['HTTP_*']
where the header key consists only of underscores, and the value only contains whitespaceI’d be happy to work on a PR for this if the maintainers agree that it’s a necessary fix.
I came across an issue whilst following https://github.com/php-runtime/psr-17#psr-7-and-psr-15-runtime to use Slim's psr-7 implementation.
At least when running with php-fpm + nginx, $_SERVER['HTTP_PORT']
is populated with a numeric string, eg 8080
. https://github.com/Nyholm/psr7-server/blob/master/src/ServerRequestCreator.php#L279 passes that string through to a UriInterface
, which with Sim's implementation results in "Uri port must be null or an integer between 1 and 65535 (inclusive)" (because it fails an is_integer check). Using nyholm/psr7 works though, as it casts the string value to an int.
I was going to raise this as an issue against slim/psr-7, but on reading the http-mesage spec it looks like withPort
should accept null|int
. I think the more correct fix is that ServerRequestCreator
should ensure that it is indeed passing in an integer or null.
I have an HTML form with an optional <input type="file">
field.
There is no problem with PHP 7.1-7.4, but with PHP 8.0 I get the following error.
Uncaught ValueError: Path cannot be empty in /Users/gr4376/Projects/webtrees/vendor/nyholm/psr7/src/Factory/Psr17Factory.php:40
Stack trace:
#0 .../vendor/nyholm/psr7/src/Factory/Psr17Factory.php(40): fopen('', 'r')
#1 .../vendor/nyholm/psr7-server/src/ServerRequestCreator.php(216): Nyholm\Psr7\Factory\Psr17Factory->createStreamFromFile('')
#2 .../vendor/nyholm/psr7-server/src/ServerRequestCreator.php(188): Nyholm\Psr7Server\ServerRequestCreator->createUploadedFileFromSpec(Array)
#3 .../vendor/nyholm/psr7-server/src/ServerRequestCreator.php(98): Nyholm\Psr7Server\ServerRequestCreator->normalizeFiles(Array)
#4 .../vendor/nyholm/psr7-server/src/ServerRequestCreator.php(71): Nyholm\Psr7Server\ServerRequestCreator->fromArrays(Array, Array, Array, Array, Array, Array, Resource id #7)
#5 .../index.php(55): Nyholm\Psr7Server\ServerRequestCreator->fromGlobals()
This is because fopen('')
gives a warning in PHP <=7.4, but a fatal error in PHP 8.0.
This is another thing developers likely want for the ServerRequest object: the request body. PHP puts this away in php://input
. Currently you would need to pass a stream to the fromArrays
method:
$requestBody = fopen('php://input', 'r');
Should fromGlobals
be extended with something like “defaults to php://input as body”?
psr/http-message hopes to support 2.0
FYI
Hello
Our server received some scripted attack attempts aimed at Wordpress (which we don't run though). These requests have headers that look like this:
0: Accept-Language: en-US,en;q=0.5
1: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
Which seems to cause the "Header name must be an RFC 7230 compatible string." exception to be thrown. It appears to be because of the header regex not accepting this, in https://github.com/Nyholm/psr7/blob/master/src/MessageTrait.php.
Is this a bug? This approach also causes a 500 to be thrown for a client error, which you'd expect to be a 400. I'm using Slim, so maybe this needs to be fixed there. I just wanted to check in here and see if you had any feedback before I bring it up with Slim.
Edit: It's thrown for any header that consists only of numbers.
Would it not make more sense to have Nyholm\Psr7\Server
to follow the other packages you have?
From php.net:
'HTTPS'
Set to a non-empty value if the script was queried through the HTTPS protocol.
This PR
HTTPS
key property.ServerRequestCreator::createUriFromArray()
method.If we rewrite this function so it does not use the UriFactory but returning a URI string instead. Then we could pass that string directly to the ServerRequestFactory.
Is that a refactoring we want to do?
Are we happy with this interface?
@Zegnat ?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.