riverside / php-express Goto Github PK
View Code? Open in Web Editor NEW:horse: PHP micro-framework inspired by Express.js
Home Page: https://riverside.github.io/php-express/
License: MIT License
:horse: PHP micro-framework inspired by Express.js
Home Page: https://riverside.github.io/php-express/
License: MIT License
Using $_SERVER['REQUEST_SCHEME'] === 'https'
is not always trustworthy. First of all, it's only available in Apache >=2.4. It doesn't even exist in nginx, IIS, lighttpd and other web servers.
Create a protected method Request::getRequestScheme()
that can properly calculate whether http or https was used. Use this function to set Request->scheme
and Request->secure
member variables.
protected static function getRequestScheme() : bool
{
// Modern servers will have the HTTPS header set to 'on' or '1'.
if (
isset($_SERVER['HTTPS'])
&& (
strtolower($_SERVER['HTTPS']) == 'on'
|| $_SERVER['HTTPS'] == 1
)
) {
return 'https';
}
// Some reverse proxies and load balencers will have the
// HTTP_X_FORWARDED_PROTO header set to 'https'.
else if (
isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
&& strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https'
) {
return 'https';
}
// Other reverse proxies and load balencers will have the
// HTTP_FRONT_END_HTTPS headers set to 'on' or '1'.
else if (
isset($_SERVER['HTTP_FRONT_END_HTTPS'])
&& (
strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) == 'on'
|| $_SERVER['HTTP_FRONT_END_HTTPS'] == 1
)
) {
return 'https';
}
// Apache server may have the REQUEST_SCHEME header available.
else if (
isset($_SERVER['REQUEST_SCHEME'])
&& strtolower($_SERVER['REQUEST_SCHEME']) == 'https'
) {
return 'https';
}
// If all else fails, try the standard SSL server port '443'.
else if (
isset($_SERVER['SERVER_PORT'])
&& intval($_SERVER['SERVER_PORT']) === 443
) {
return 'https';
}
return 'http';
}
has php-express default error (notFound) method to show 404 error page ?
any hints to write this ? how to do it ?
Thanks for your work on this project. I'm planning on using it to put together a simple HTMX example app.
It would be interesting to add in optional support for the Twig template engine. Regardless of anyone's stance on Symfony, it is a fantastic template language and doesn't even require the entire Symfony package ecosystem to use it standalone.
Something like this would be cool:
composer require twig/twig
$app = new \PhpExpress\Application();
$app->set('views', 'path/to/views');
$app->set('twig_options', [
'cache' => 'path/to/twig_cache',
// Uncomment for local development only.
// 'debug' => true,
// 'auto_reload' => true,
]);
$app->get('/', function ($req, $res) {
$res->render('base', [
'title' => 'Home page',
'message' => 'This is the home page',
]);
});
$app->get('about', function ($req, $res) {
$res->render('about', [
'title' => 'About page',
'message' => 'This is the about page',
]);
});
Then in template folder we have:
views/base.twig:
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
{% block header %}
<h1>{{ title }}</h1>
{% endblock %}
{% block content %}
<div>{{ content }}</div>
<a href="/about">About</a>
{% endblock %}
</body>
</html>
views/about.html.twig:
{% extends "base.twig" %}
{% block content %}
<div>{{ content }}</div>
<a href="/">Home</a>
{% endblock %}
In Application::render()
we can hand down local variables into the Twig template if a matching view filename with extension .twig
is found.
Then we can check if Twig FilesystemLoader class exists. The following is working for me:
public function render(string $view, array $locals=null): void
{
if ($locals)
{
extract($locals);
}
$views_dir = $this->set("views");
$layout = sprintf("%s/%s.php", $views_dir, $view);
$_twig = sprintf("%s/%s.twig", $views_dir, $view);
$_template = sprintf("%s/%s.php", $views_dir, $this->set("template"));
if (is_file($_template))
{
include $_template;
} elseif (is_file($_twig)) {
if (!class_exists('\Twig\Loader\FilesystemLoader')) {
$filepath = realpath($_twig);
throw new \Exception("Please `composer require twig/twig` to proceed. A Twig template '{$filepath}' was found but the Twig template engine could not be loaded");
}
$loader = new \Twig\Loader\FilesystemLoader($views_dir);
$twig = new \Twig\Environment($loader, $this->set("twig_options"));
echo $twig->render(sprintf('%s.twig', $view), $locals);
} else {
include $layout;
}
}
I have a class named Middleware and all the middlewares are declared as static functions in that class. How can I pass any of the function to use it as middleware. I tried following code but it does not work.
$app->use(Middlewares::setDeveloperHeader); // Here setDeveloperHeader is a public static function of class Middlewares
Any help would be appreciated.
Support for PUT, PATCH, DELETE verbs exist (Eg \PhpExpress\Application::put()
and \PhpExpress\Application::patch()
) but are of limited use because there is no payload data populated into in the Request
object.
$app = new \PhpExpress\Application();
$testVerbs = function($req, $res) {
echo "method:" . var_export($req->method, TRUE) . PHP_EOL;
echo "content-type:" . var_export($req->get("content-type"), TRUE) . PHP_EOL;
echo "params:" . var_export($req->params, TRUE) . PHP_EOL;
echo "body:" . var_export($req->body, TRUE) . PHP_EOL;
$res->end();
};
$app->get('contact/:id', $testVerbs);
$app->post('contact/:id', $testVerbs);
$app->put('contact/:id', $testVerbs);
$app->patch('contact/:id', $testVerbs);
curl -X GET -d argument=value -d argument2=value2 http://localhost:8000/contact/1
curl -X POST -d argument=value -d argument2=value2 http://localhost:8000/contact/1
curl -X PUT -d argument=value -d argument2=value2 http://localhost:8000/contact/1
curl -X PATCH -d argument=value -d argument2=value2 http://localhost:8000/contact/1
content-type:'application/x-www-form-urlencoded'
params:array (
'id' => '1',
)
body:array (
'argument' => 'value',
'argument2' => 'value2',
)
But the actual result varies by HTTP Request Method.
Only the POST request type matches the expected result above with a populated $req->body
All others show an empty body:
content-type:'application/x-www-form-urlencoded'
params:array (
'id' => '1',
)
body:array (
)
Populate the $req->body
with the payload from PHP's Standard Input stream via PHP's parse_str()
when $_POST is empty. For simplicity, since the $req->body is just a pointer to $_POST superglobal, we can parse the data into $_POST
directly which is guaranteed to be empty for any HTTP request method other than POST.
parse_str(file_get_contents('php://input'), $_POST);
Forms can be submitted with different encoding types in the Content-Type
header. application/x-www-form-urlencoded
is the default, but multipart/form-data
could also be accepted. However handling files uploaded with multipart/form-data
encoding via HTTP PUT is not supported in PHP <8.4, therefore the parsing has to be done in different ways.
Full and future-proof solution, for when php 8.4 drops in November 2024:
// Make data payloads available in $this->body for other HTTP verbs.
if (
$this->method !== 'POST'
&& $this->is('application/x-www-form-urlencoded')
) {
parse_str(file_get_contents('php://input'), $_POST);
}
// Add support for multipart/form-data parsing for other HTTP verbs in PHP >=8.4.
if (
$this->method !== 'POST'
&& $this->is('multipart/form-data')
&& function_exists('request_parse_body')
) {
[$_POST, $_FILES] = call_user_func('request_parse_body');
}
Hi!
I have read code and documentation provided but I couldn't find a way to pass parameters like we do in express.js. Yeah I did find a way to pass "hash" and numeric "id" but not a custom parameter.
$app.get('/user/:username', function ($req, $res) {
$res->send($req->params['username']);
}
Is there a way to do that in php-express?
At the line 207, set $domain = isset($options['domain']) ? $options['domain'] : "";
to $domain = isset($options['domain']) ? $options['domain'] : "/";
for clear cookies correctly
is it possible to suggest $_SERVER['REQUEST_URI']
instead of $_GET['_path_']
?
https://github.com/riverside/php-express/blob/master/examples/02-views/index.php
it will only show the root route, and the link to the next page is broken. i've been using php7.3 dev server to test the examples.
It is giving not found error on all pages except "/" route. And I have tested it on basic example. Nothing Complex.
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . "/vendor/autoload.php";
use \PhpExpress\Application;
$app = new Application();
$app->get("/", function ($req, $res) {
$res->send("Root");
});
$app->get("/test", function ($req, $res) {
$res->send("Test");
});
$app->run();
PHP Version: 7.4
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.