Author: Shivam Mathur (shivammathur) Date: 2024-07-08T00:27:31+05:30 Commit: https://github.com/php/web-downloads/commit/2dd6a7cc2c19c5ce43d840541ebf6ca5eba55871 Raw diff: https://github.com/php/web-downloads/commit/2dd6a7cc2c19c5ce43d840541ebf6ca5eba55871.diff
Add routing and Auth Changed paths: A .env.example A .gitignore A bootstrap.php A composer.json A composer.lock A public/index.php A routes.php A src/Auth.php A src/IndexHandler.php A src/PeclHandler.php A src/PhpHandler.php A src/Router.php A src/Validator.php A src/WinlibsHandler.php A src/scripts/common.sh A src/scripts/pecl.sh A src/scripts/php.sh A src/scripts/winlibs.sh D src/pecl.sh D src/php.sh D src/run.php D src/winlibs.sh Diff: diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e64e685 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +AUTH_TOKEN= +BUILDS_DIRECTORY= +SCRIPTS_USER= \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d5163b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +.env diff --git a/bootstrap.php b/bootstrap.php new file mode 100644 index 0000000..54248d2 --- /dev/null +++ b/bootstrap.php @@ -0,0 +1,10 @@ +<?php + +require_once __DIR__.'/vendor/autoload.php'; + +use Dotenv\Dotenv; + +$dotenv = Dotenv::createImmutable(__DIR__); +$dotenv->load(); + +require_once __DIR__.'/routes.php'; diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..89846d4 --- /dev/null +++ b/composer.json @@ -0,0 +1,16 @@ +{ + "name": "php/web-downloads", + "description": "Scripts for downloads.php.net", + "type": "project", + "license": "MIT", + "autoload": { + "psr-4": { + "App\\": "src/" + } + }, + "require": { + "php": "^8.2", + "vlucas/phpdotenv": "^5.6", + "symfony/process": "^7.1" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..6fc5314 --- /dev/null +++ b/composer.lock @@ -0,0 +1,542 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "4e249ba8959f6a2c56b273e97dedc5a5", + "packages": [ + { + "name": "graham-campbell/result-type", + "version": "v1.1.2", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/fbd48bce38f73f8a4ec8583362e732e4095e5862", + "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "he...@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2023-11-12T22:16:48+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.2", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/80735db690fe4fc5c76dfa7f9b770634285fa820", + "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmitt...@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "he...@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2023-11-12T21:59:55+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "backend...@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p...@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-19T12:30:46+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", + "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.ba...@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p...@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "symfony/process", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "febf90124323a093c7ee06fdb30e765ca3c20028" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/febf90124323a093c7ee06fdb30e765ca3c20028", + "reference": "febf90124323a093c7ee06fdb30e765ca3c20028", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fab...@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:57:53+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4", + "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.2", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.2", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "he...@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "va...@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2023-11-12T22:43:29+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": "^8.2" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..f2fe731 --- /dev/null +++ b/public/index.php @@ -0,0 +1,7 @@ +<?php + +// Register the Composer autoloader... +require_once __DIR__.'/../vendor/autoload.php'; + +// Init +require_once __DIR__ . '/../bootstrap.php'; diff --git a/routes.php b/routes.php new file mode 100644 index 0000000..dbd8441 --- /dev/null +++ b/routes.php @@ -0,0 +1,11 @@ +<?php + +use App\IndexHandler; +use App\Router; + +$router = new Router(); +$router->registerRoute('/', 'GET', IndexHandler::class); +$router->registerRoute('/pecl', 'POST', PeclHandler::class, true); +$router->registerRoute('/winlibs', 'POST', WinlibsHandler::class, true); +$router->registerRoute('/php', 'POST', PhpHandler::class, true); +$router->handleRequest(); diff --git a/src/Auth.php b/src/Auth.php new file mode 100644 index 0000000..26dd4b6 --- /dev/null +++ b/src/Auth.php @@ -0,0 +1,14 @@ +<?php + +namespace App; + +class Auth +{ + public function authenticate(): bool + { + $authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; + $authToken = str_replace('Bearer ', '', $authHeader); + + return $authToken === $_ENV['AUTH_TOKEN']; + } +} diff --git a/src/IndexHandler.php b/src/IndexHandler.php new file mode 100644 index 0000000..c15db73 --- /dev/null +++ b/src/IndexHandler.php @@ -0,0 +1,10 @@ +<?php + +namespace App; +class IndexHandler +{ + public function handle(): void + { + echo 'Welcome!'; + } +} \ No newline at end of file diff --git a/src/PeclHandler.php b/src/PeclHandler.php new file mode 100644 index 0000000..0310c1d --- /dev/null +++ b/src/PeclHandler.php @@ -0,0 +1,9 @@ +<?php + +class PeclHandler +{ + + public function handle() + { + } +} \ No newline at end of file diff --git a/src/PhpHandler.php b/src/PhpHandler.php new file mode 100644 index 0000000..61ffbc3 --- /dev/null +++ b/src/PhpHandler.php @@ -0,0 +1,9 @@ +<?php + +class PhpHandler +{ + + public function handle() + { + } +} \ No newline at end of file diff --git a/src/Router.php b/src/Router.php new file mode 100644 index 0000000..7d16d5f --- /dev/null +++ b/src/Router.php @@ -0,0 +1,55 @@ +<?php + +namespace App; + +class Router +{ + private array $routes = []; + private Auth $auth; + + public function __construct() + { + $this->auth = new Auth(); + } + + public function registerRoute(string $path, string $method, string $handler, bool $requiresAuth = false): void + { + $this->routes[$method][$path] = [ + 'handler' => $handler, + 'requiresAuth' => $requiresAuth + ]; + } + + public function handleRequest(): void + { + $path = $_SERVER['REQUEST_URI']; + $method = $_SERVER['REQUEST_METHOD']; + + $allowedMethods = []; + + foreach ($this->routes as $registeredMethod => $paths) { + if (isset($paths[$path])) { + $allowedMethods[] = $registeredMethod; + } + } + + if (isset($this->routes[$method][$path])) { + $route = $this->routes[$method][$path]; + + if ($route['requiresAuth'] && !$this->auth->authenticate()) { + http_response_code(401); + echo 'Unauthorized'; + return; + } + + $handler = $route['handler']; + (new $handler)->handle(); + } elseif (!empty($allowedMethods)) { + http_response_code(405); + echo 'Method Not Allowed. Allowed methods: ' . implode(', ', $allowedMethods); + } else { + http_response_code(404); + echo 'Not Found'; + } + } +} diff --git a/src/Validator.php b/src/Validator.php new file mode 100644 index 0000000..345ac19 --- /dev/null +++ b/src/Validator.php @@ -0,0 +1,59 @@ +<?php + +namespace App; + +class Validator +{ + protected array $errors = []; + + public function validate(array $data, array $rules): bool + { + $this->errors = []; + + foreach ($rules as $field => $ruleString) { + $rulesArray = explode('|', $ruleString); + foreach ($rulesArray as $rule) { + $ruleParts = explode(':', $rule); + $ruleName = $ruleParts[0]; + $ruleValue = $ruleParts[1] ?? null; + + if (!$this->$ruleName($data[$field] ?? null, $ruleValue)) { + $this->errors[$field][] = $this->getErrorMessage($field, $ruleName); + } + } + } + + return empty($this->errors); + } + + public function errors(): array + { + return $this->errors; + } + + protected function required($value): bool + { + return !is_null($value) && $value !== ''; + } + + protected function url($value): bool + { + return filter_var($value, FILTER_VALIDATE_URL) !== false; + } + + protected function string($value): bool + { + return is_string($value); + } + + protected function getErrorMessage($field, $rule): string + { + $messages = [ + 'required' => "The $field field is required.", + 'url' => "The $field field must be a valid URL.", + 'string' => "The $field field must be a string.", + ]; + + return $messages[$rule] ?? "The $field field has an invalid value."; + } +} diff --git a/src/WinlibsHandler.php b/src/WinlibsHandler.php new file mode 100644 index 0000000..8af13c8 --- /dev/null +++ b/src/WinlibsHandler.php @@ -0,0 +1,9 @@ +<?php + +class WinlibsHandler +{ + + public function handle() + { + } +} \ No newline at end of file diff --git a/src/pecl.sh b/src/pecl.sh deleted file mode 100644 index 544ce32..0000000 --- a/src/pecl.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -# Fetch PECL extension builds diff --git a/src/run.php b/src/run.php deleted file mode 100644 index 215a1fb..0000000 --- a/src/run.php +++ /dev/null @@ -1,3 +0,0 @@ -<?php - -// TODO: Implement the run function \ No newline at end of file diff --git a/src/scripts/common.sh b/src/scripts/common.sh new file mode 100644 index 0000000..b9c4c94 --- /dev/null +++ b/src/scripts/common.sh @@ -0,0 +1,10 @@ +function fetch_artifact() { + local filepath=$1 + local url=$2 + local token=$3 + if [[ "$url" == *api.github.com* ]]; then + curl -H "Accept: application/vnd.github+json" -H "Authorization: token $token" -L -o "$filepath" "$url" + else + curl -L -o "$filepath" "$url" + fi +} \ No newline at end of file diff --git a/src/scripts/pecl.sh b/src/scripts/pecl.sh new file mode 100644 index 0000000..222a175 --- /dev/null +++ b/src/scripts/pecl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +# TODO: Fetch PECL builds diff --git a/src/php.sh b/src/scripts/php.sh similarity index 100% rename from src/php.sh rename to src/scripts/php.sh diff --git a/src/winlibs.sh b/src/scripts/winlibs.sh similarity index 100% rename from src/winlibs.sh rename to src/scripts/winlibs.sh