Commit: ae57162e8dce7a000a1e3ea3e05387a9263ef0bc
Author: Peter Kokot <[email protected]> Sun, 16 Dec 2018 09:45:38
+0100
Parents: 6712d9e13cdc37af96018976ac50b4b1c62b5604
Branches: master
Link:
http://git.php.net/?p=web/bugs.git;a=commitdiff;h=ae57162e8dce7a000a1e3ea3e05387a9263ef0bc
Log:
Refactor fetching versions
- Procedural code moved to OOP
- Added unit tests
- Added a more flexible tmp folder location and introduce var folder
(in production this won't work yet, so we still use /tmp there).
For local development environments var directory in project root
is used for faster and easier project setup.
- Added initial extensible PSR-16-alike semi-compatible cache class
and refactored storing fetched versions.
- The versions list generator is now simpler and a bit more logical
what is happening. Versions sort order is the same as before.
- Added ComposerScripts utility/service class for creating required
directories (uploads and var/cache), and configuration file, when
installing application in development environment.
Changed paths:
M .gitignore
M README.md
M composer.json
D include/php_versions.php
A src/Utils/Cache.php
A src/Utils/ComposerScripts.php
A src/Utils/Versions/Client.php
A src/Utils/Versions/Generator.php
A tests/Utils/CacheTest.php
A tests/Utils/Versions/ClientTest.php
A tests/Utils/Versions/GeneratorTest.php
A tests/fixtures/versions/versions.php
A tests/mock/responses/dev-body.txt
A tests/mock/responses/stable-body.txt
M www/report.php
diff --git a/.gitignore b/.gitignore
index 6c2d011..07c61bc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,5 +7,8 @@
# Local specific PHPUnit configuration
/phpunit.xml
+# Transient and temporary generated files
+/var/
+
# Generated by Composer
/vendor/
diff --git a/README.md b/README.md
index 526ee6a..e24aca4 100644
--- a/README.md
+++ b/README.md
@@ -5,12 +5,6 @@ This is a unified bug tracking system for PHP hosted online at
## Local installation
-* Copy configuration and modify it accordingly for your local system:
-
-```bash
-cp local_config.php.sample local_config.php
-```
-
* Install development dependencies with Composer:
```bash
@@ -24,6 +18,10 @@ pear channel-update pear.php.net
pear install --alldeps Text_Diff
```
+* Configuration:
+
+Modify `local_config.php` according to your local development environment.
+
* Database:
Create a new MySQL/MariaDB database using `sql/database.sql`, create database
@@ -58,6 +56,7 @@ Source code of this application is structured in the
following directories:
├─ templates/ # Application templates
├─ tests/ # Application automated tests
├─ uploads/ # Uploaded patch files
+ ├─ var/ # Transient and temporary generated files
├─ vendor/ # Dependencies generated by Composer
└─ www/ # Publicly accessible directory for online
bugs.php.net
├─ css/ # Stylesheets
diff --git a/composer.json b/composer.json
index a4fea73..cddad87 100644
--- a/composer.json
+++ b/composer.json
@@ -42,5 +42,11 @@
"psr-4": {
"App\\Tests\\": "tests/"
}
+ },
+ "scripts":{
+ "post-install-cmd": [
+ "App\\Utils\\ComposerScripts::installConfig",
+ "App\\Utils\\ComposerScripts::createDirectories"
+ ]
}
}
diff --git a/include/php_versions.php b/include/php_versions.php
deleted file mode 100644
index 8aa07af..0000000
--- a/include/php_versions.php
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-
-/*
-The RC and dev versions are pulled from the https://qa.php.net/api.php
-if you want to add a new version, add it there at include/release-qa.php
-the result is cached for an hour in /tmp/<systemd>/tmp/versions.php
-the versions are weighted by the following:
-- major+minor version desc (7>5.4>5.3>master)
-- between a minor version we order by the micro if available: first the qa
releases: alpha/beta/rc, then the stable, then the Git versions(snaps, Git)
-
-Stable releases are pulled from https://php.net/releases/active.php
-*/
-
-// Custom versions appended to the list
-$custom_versions = [
- 'Next Major Version',
- 'Next Minor Version',
- 'Irrelevant'
-];
-
-if(!file_exists("/tmp/versions.php") || filemtime("/tmp/versions.php") <
$_SERVER['REQUEST_TIME'] - 3600) {
- $versions = buildVersions();
- $versions_data = var_export($versions, true);
- file_put_contents("/tmp/versions.php", '<?php $versions =
'.$versions_data.';');
-} else {
- include "/tmp/versions.php";
-}
-
-$versions = array_merge($versions, $custom_versions);
-
-function buildVersions() {
- $dev_versions =
json_decode(file_get_contents('https://qa.php.net/api.php?type=qa-releases&format=json&only=dev_versions'));
-
- $versions = [];
-
- $date = date('Y-m-d');
- $default_versions = [
- "Git-{$date} (snap)",
- "Git-{$date} (Git)",
- ];
-
- foreach ($dev_versions as $dev_version) {
- $dev_version_parts = parseVersion($dev_version);
-
- // if it is a dev version, then add that branch, add the
minor-1 version, if it's appropriate
- if ($dev_version_parts['type'] == 'dev') {
- if
(!isset($versions[$dev_version_parts['major']][$dev_version_parts['minor']])) {
-
$versions[$dev_version_parts['major']][$dev_version_parts['minor']] = [];
- }
- }
- // then it is a qa version (alpha|beta|rc)
- else {
-
$versions[$dev_version_parts['major']][$dev_version_parts['minor']][$dev_version_parts['micro']]
= $dev_version_parts;
-
ksort($versions[$dev_version_parts['major']][$dev_version_parts['minor']]);
- }
- }
-
- $stable_releases =
json_decode(file_get_contents('https://php.net/releases/active.php'), true);
- foreach ($stable_releases as $major => $major_releases) {
- foreach ($major_releases as $release) {
- $version_parts = parseVersion($release['version']);
-
$versions[$version_parts['major']][$version_parts['minor']][$version_parts['micro']]
= $version_parts;
-
ksort($versions[$version_parts['major']][$version_parts['minor']]);
- }
- }
-
- $flat_versions = [];
-
- // add master to the end of the list
- foreach ($default_versions as $default_version) {
- $flat_versions[] = 'master-'.$default_version;
- }
-
- // add the fetched versions to the list
- foreach ($versions as $major_number => $major) {
- foreach ($major as $minor_number => $minor) {
- // add the default versions to ever minor branch
- foreach ($default_versions as $default_version) {
- $flat_versions[] =
$major_number.'.'.$minor_number.$default_version;
- }
- foreach ($minor as $micro_number => $micro) {
- $flat_versions[] = $micro['original_version'];
- }
- }
- }
-
- // reverse the order, this makes it descending
- $flat_versions = array_reverse($flat_versions);
-
- return $flat_versions;
-}
-
-function parseVersion($version){
- $version_parts = [];
- $raw_parts = [];
-
preg_match('#(?P<major>\d+)\.(?P<minor>\d+).(?P<micro>\d+)[-]?(?P<type>RC|alpha|beta|dev)?(?P<number>[\d]?).*#ui',
$version, $raw_parts);
- $version_parts = [
- 'major' => $raw_parts['major'],
- 'minor' => $raw_parts['minor'],
- 'micro' => $raw_parts['micro'],
- 'type' =>
strtolower($raw_parts['type']?$raw_parts['type']:'stable'),
- 'number' => $raw_parts['number'],
- 'original_version' => $version,
- ];
- return $version_parts;
-}
diff --git a/src/Utils/Cache.php b/src/Utils/Cache.php
new file mode 100644
index 0000000..2cf29a5
--- /dev/null
+++ b/src/Utils/Cache.php
@@ -0,0 +1,157 @@
+<?php
+
+namespace App\Utils;
+
+/**
+ * A simple cache service for storing data in file(s).
+ */
+class Cache
+{
+ /**
+ * Pool of items.
+ *
+ * @var array
+ */
+ private $pool = [];
+
+ /**
+ * Temporary cache directory where data is stored.
+ *
+ * @var string
+ */
+ private $dir;
+
+ /**
+ * Default time after cache file is considered expired in seconds.
+ */
+ public const TTL = 3600;
+
+ /**
+ * Class constructor.
+ */
+ public function __construct(string $dir)
+ {
+ $this->dir = $dir;
+
+ // Create cache directory if it doesn't exist.
+ if (!file_exists($this->dir)) {
+ mkdir($this->dir, 0777, true);
+ chmod($this->dir, 0777);
+ }
+
+ // Validate cache directory
+ if (!is_dir($this->dir)) {
+ throw new \Exception($this->dir.' is not a valid directory.');
+ }
+ }
+
+ /**
+ * Write data to cache file.
+ */
+ public function set(string $key, $data, int $ttl = self::TTL): void
+ {
+ if (!$this->validateKey($key)) {
+ throw new Exception('Key name '.$key.' is invalid.');
+ }
+
+ $item = [time() + $ttl, serialize($data)];
+ $this->pool[$key] = $data;
+
+ $string = '<?php return '.var_export($item, true).";\n";
+
+ file_put_contents($this->dir.'/'.$key.'.php', $string);
+ }
+
+ /**
+ * Check if item has been cached and is available.
+ */
+ public function has(string $key): bool
+ {
+ if (isset($this->pool[$key])) {
+ return true;
+ }
+
+ $file = $this->dir.'/'.$key.'.php';
+
+ if (!is_file($file)) {
+ return false;
+ }
+
+ $data = require $file;
+
+ if (is_array($data) && isset($data[0]) && is_int($data[0]) && time() <
$data[0]) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get data from the cache pool.
+ */
+ public function get(string $key): ?array
+ {
+ if (isset($this->pool[$key])) {
+ return $this->pool[$key];
+ }
+
+ $file = $this->dir.'/'.$key.'.php';
+
+ if (is_file($file)) {
+ $data = require $file;
+ $this->pool[$key] = unserialize($data[1]);
+
+ return $this->pool[$key];
+ }
+
+ return null;
+ }
+
+ /**
+ * Wipes entire cache.
+ */
+ public function clear(): bool
+ {
+ $success = true;
+
+ $this->pool = [];
+
+ foreach (new \DirectoryIterator($this->dir) as $fileInfo) {
+ if ($fileInfo->isDot()) {
+ continue;
+ }
+
+ if (!unlink($fileInfo->getRealPath())) {
+ $success = false;
+ }
+ }
+
+ return $success;
+ }
+
+ /**
+ * Delete item from the cache.
+ */
+ public function delete(string $key): bool
+ {
+ $success = true;
+
+ unset($this->pool[$key]);
+
+ $file = $this->dir.'/'.$key.'.php';
+
+ if (is_file($file) && !unlink($file)) {
+ $success = false;
+ }
+
+ return $success;
+ }
+
+ /**
+ * Validate key.
+ */
+ private function validateKey(string $key): bool
+ {
+ return (bool) preg_match('/[a-z\_\-0-9]/i', $key);
+ }
+}
diff --git a/src/Utils/ComposerScripts.php b/src/Utils/ComposerScripts.php
new file mode 100644
index 0000000..769856d
--- /dev/null
+++ b/src/Utils/ComposerScripts.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace App\Utils;
+
+use Composer\Script\Event;
+
+/**
+ * Service for running Composer scripts when installing application.
+ */
+class ComposerScripts
+{
+ private static $cacheDir = __DIR__.'/../../var/cache';
+ private static $uploadsDir = __DIR__.'/../../uploads';
+
+ /**
+ * Create a default configuration settings for the development environment.
+ */
+ public static function installConfig(Event $event)
+ {
+ $sampleFile = __DIR__.'/../../local_config.php.sample';
+ $targetFile = __DIR__.'/../../local_config.php';
+
+ if ($event->isDevMode() && !file_exists($targetFile)) {
+ copy($sampleFile, $targetFile);
+ }
+ }
+
+ /**
+ * Create application temporary and upload directories which are not
tracked
+ * in Git.
+ */
+ public static function createDirectories(Event $event)
+ {
+ if (!$event->isDevMode()) {
+ return;
+ }
+
+ $vendorDir = $event->getComposer()->getConfig()->get('vendor-dir');
+
+ require_once $vendorDir.'/autoload.php';
+
+ if (!file_exists(self::$cacheDir)) {
+ mkdir(self::$cacheDir, 0777, true);
+ chmod(self::$cacheDir, 0777);
+ }
+
+ if (!file_exists(self::$uploadsDir)) {
+ mkdir(self::$uploadsDir, 0777, true);
+ chmod(self::$uploadsDir, 0777);
+ }
+ }
+}
diff --git a/src/Utils/Versions/Client.php b/src/Utils/Versions/Client.php
new file mode 100644
index 0000000..bf91a9c
--- /dev/null
+++ b/src/Utils/Versions/Client.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Utils\Versions;
+
+/**
+ * API client for sending requests to PHP API pages.
+ */
+class Client
+{
+ /**
+ * API URL for fetching development PHP versions.
+ *
+ * @var string
+ */
+ private $devVersionsUrl =
'https://qa.php.net/api.php?type=qa-releases&format=json&only=dev_versions';
+
+ /**
+ * API URL for fetching active PHP versions.
+ *
+ * @var string
+ */
+ private $stableVersionsUrl = 'https://php.net/releases/active.php';
+
+ /**
+ * Fetches data from remote URL.
+ */
+ public function fetchDevVersions(): array
+ {
+ $json = file_get_contents($this->devVersionsUrl);
+
+ return json_decode($json, true);
+ }
+
+ /**
+ * Fetch stable versions from remote URL.
+ */
+ public function fetchStableVersions(): array
+ {
+ $json = file_get_contents($this->stableVersionsUrl);
+
+ return json_decode($json, true);
+ }
+}
diff --git a/src/Utils/Versions/Generator.php b/src/Utils/Versions/Generator.php
new file mode 100644
index 0000000..0631c46
--- /dev/null
+++ b/src/Utils/Versions/Generator.php
@@ -0,0 +1,185 @@
+<?php
+
+namespace App\Utils\Versions;
+
+use App\Utils\Cache;
+
+/**
+ * Service for retrieving a list of valid PHP versions when reporting bugs. PHP
+ * versions have format MAJOR.MINOR.MICRO{TYPE} where TYPE is one of alpha,
+ * beta, RC, or dev.
+ *
+ * Stable releases are pulled from the https://php.net. The RC and dev versions
+ * are pulled from the https://qa.php.net.
+ *
+ * To add a new PHP version add it to:
+ * https://git.php.net/?p=web/qa.git;a=blob;f=include/release-qa.php
+ *
+ * The versions are weighted by the following criteria:
+ * - major+minor version desc (7>5.4>5.3>master)
+ * - Between minor versions ordering is done by the micro version if available.
+ * First the QA releases: alpha/beta/rc, then stable, then nightly versions
+ * (Git, snaps). Snaps are more or less Windows snapshot builds.
+ *
+ * The result is cached for 1 hour into a temporary file.
+ */
+class Generator
+{
+ /**
+ * PHP API pages client.
+ *
+ * @var Client
+ */
+ private $client;
+
+ /**
+ * Cache service for storing fetched versions.
+ *
+ * @var Cache
+ */
+ private $cache;
+
+ /**
+ * Time after cache file is considered expired in seconds.
+ */
+ private const TTL = 3600;
+
+ /**
+ * Additional versions appended to the list of generated versions.
+ */
+ private const APPENDICES = [
+ 'Next Major Version',
+ 'Next Minor Version',
+ 'Irrelevant',
+ ];
+
+ /**
+ * Class constructor.
+ */
+ public function __construct(Client $client, Cache $cache)
+ {
+ $this->client = $client;
+ $this->cache = $cache;
+ }
+
+ /**
+ * Get a list of valid PHP versions. Versions are cached for efficiency.
+ */
+ public function getVersions(): array
+ {
+ if (!$this->cache->has('versions')) {
+ $this->cache->set('versions', $this->generateVersions(),
self::TTL);
+ }
+
+ return $this->cache->get('versions');
+ }
+
+ /**
+ * Return fetched and processed versions.
+ */
+ private function generateVersions(): array
+ {
+ $versions = array_merge($this->getDevVersions(),
$this->getStableVersions());
+ rsort($versions);
+
+ // Get minor branches (PHP 7.2, PHP 7.3, etc)
+ $branches = [];
+ foreach ($versions as $version) {
+ $parts = $this->parseVersion($version);
+ $branch = $parts['major'].'.'.$parts['minor'];
+ $branches[$branch] = $branch;
+ }
+
+ $sorted = [];
+
+ // Add versions grouped by branches
+ foreach ($branches as $branch) {
+ foreach ($versions as $version) {
+ $parts = $this->parseVersion($version);
+ if ($parts['major'].'.'.$parts['minor'] === $branch) {
+ $sorted[] = $version;
+ }
+ }
+
+ // Append Git and snaps for each branch
+ foreach ($this->getAffixes() as $item) {
+ $sorted[] = $branch.$item;
+ }
+ }
+
+ // Append master branch to the versions list
+ foreach ($this->getAffixes() as $item) {
+ $sorted[] = 'master-'.$item;
+ }
+
+ // Append human readable versions
+ $sorted = array_merge($sorted, self::APPENDICES);
+
+ return $sorted;
+ }
+
+ /**
+ * Get version affixes such as Git or snapshots.
+ */
+ protected function getAffixes(): array
+ {
+ $date = date('Y-m-d');
+
+ return [
+ 'Git-'.$date.' (Git)',
+ 'Git-'.$date.' (snap)',
+ ];
+ }
+
+ /**
+ * Get alpha, beta and RC versions.
+ */
+ private function getDevVersions(): array
+ {
+ $versions = [];
+
+ foreach ($this->client->fetchDevVersions() as $version) {
+ $parts = $this->parseVersion($version);
+ if ('dev' !== $parts['type']) {
+ $versions[] = $version;
+ }
+ }
+
+ return $versions;
+ }
+
+ /**
+ * Get stable versions.
+ */
+ private function getStableVersions(): array
+ {
+ $versions = [];
+
+ foreach ($this->client->fetchStableVersions() as $releases) {
+ foreach ($releases as $release) {
+ $versions[] = $release['version'];
+ }
+ }
+
+ return $versions;
+ }
+
+ /**
+ * Parse the versions data string and convert it to array.
+ */
+ private function parseVersion(string $version): array
+ {
+ $matches = [];
+
preg_match('#(?P<major>\d+)\.(?P<minor>\d+).(?P<micro>\d+)[-]?(?P<type>RC|alpha|beta|dev)?(?P<number>[\d]?).*#ui',
$version, $matches);
+ $parts = [
+ 'major' => $matches['major'],
+ 'minor' => $matches['minor'],
+ 'micro' => $matches['micro'],
+ 'type' => strtolower($matches['type'] ? $matches['type'] :
'stable'),
+ 'number' => $matches['number'],
+ 'original' => $version,
+ ];
+
+ return $parts;
+ }
+}
diff --git a/tests/Utils/CacheTest.php b/tests/Utils/CacheTest.php
new file mode 100644
index 0000000..0e045ed
--- /dev/null
+++ b/tests/Utils/CacheTest.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Tests\Utils;
+
+use App\Utils\Cache;
+use PHPUnit\Framework\TestCase;
+
+class CacheTest extends TestCase
+{
+ private $cacheDir = __DIR__.'/../../var/cache/test';
+ private $cache;
+
+ public function setUp()
+ {
+ $this->cache = new Cache($this->cacheDir);
+ $this->cache->clear();
+ }
+
+ public function tearDown()
+ {
+ $this->cache->clear();
+ rmdir($this->cacheDir);
+ }
+
+ public function testHas()
+ {
+ $this->assertFalse($this->cache->has('foo'));
+
+ $this->cache->set('foo', [1, 2, 3]);
+ $this->assertTrue($this->cache->has('foo'));
+ }
+
+ public function testDelete()
+ {
+ $this->cache->set('bar', [1, 2, 3]);
+ $this->assertFileExists($this->cacheDir.'/bar.php');
+
+ $this->cache->delete('bar');
+ $this->assertFalse(file_exists($this->cacheDir.'/bar.php'));
+ }
+}
diff --git a/tests/Utils/Versions/ClientTest.php
b/tests/Utils/Versions/ClientTest.php
new file mode 100644
index 0000000..54f3ec0
--- /dev/null
+++ b/tests/Utils/Versions/ClientTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace App\Tests\Utils\Versions;
+
+use PHPUnit\Framework\TestCase;
+use App\Utils\Versions\Client;
+
+class ClientTest extends TestCase
+{
+ private $client;
+
+ public function setUp()
+ {
+ $this->client = new Client();
+
+ $reflection = new \ReflectionClass($this->client);
+
+ $devVersionsUrl = $reflection->getProperty('devVersionsUrl');
+ $devVersionsUrl->setAccessible(true);
+ $devVersionsUrl->setValue($this->client,
__DIR__.'/../../mock/responses/dev-body.txt');
+
+ $stableVersionsUrl = $reflection->getProperty('stableVersionsUrl');
+ $stableVersionsUrl->setAccessible(true);
+ $stableVersionsUrl->setValue($this->client,
__DIR__.'/../../mock/responses/stable-body.txt');
+ }
+
+ public function testFetchDevVersions()
+ {
+ $this->assertInternalType('array', $this->client->fetchDevVersions());
+ }
+
+ public function testFetchStableVersions()
+ {
+ $this->assertInternalType('array',
$this->client->fetchStableVersions());
+ }
+}
diff --git a/tests/Utils/Versions/GeneratorTest.php
b/tests/Utils/Versions/GeneratorTest.php
new file mode 100644
index 0000000..386a5b6
--- /dev/null
+++ b/tests/Utils/Versions/GeneratorTest.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace App\Tests\Utils\Versions;
+
+use PHPUnit\Framework\TestCase;
+use App\Utils\Versions\Generator;
+use App\Utils\Versions\Client;
+use App\Utils\Cache;
+
+class GeneratorTest extends TestCase
+{
+ private $cacheDir = __DIR__.'/../../../var/cache/test';
+ private $cache;
+ private $client;
+ private $generator;
+
+ public function setUp()
+ {
+ $this->cache = new Cache($this->cacheDir);
+ $this->cache->clear();
+
+ // The results returned by the client depend on the remote URLs so we
+ // mock the returned results.
+ $this->client = $this->getMockBuilder(Client::class)
+ ->setMethods(['fetchDevVersions', 'fetchStableVersions'])
+ ->getMock();
+
+ $this->client->expects($this->once())
+ ->method('fetchDevVersions')
+
->will($this->returnValue(json_decode(file_get_contents(__DIR__.'/../../mock/responses/dev-body.txt',
true))));
+
+ $this->client->expects($this->once())
+ ->method('fetchStableVersions')
+
->will($this->returnValue(json_decode(file_get_contents(__DIR__.'/../../mock/responses/stable-body.txt'),
true)));
+
+ $this->generator = $this->getMockBuilder(Generator::class)
+ ->setConstructorArgs([$this->client, $this->cache])
+ ->setMethods(['getAffixes'])
+ ->getMock();
+
+ // The extra versions are always date dependant so we mock it to
include
+ // static date done on the tests day.
+ $date = '2018-12-26';
+ $this->generator->expects($this->any())
+ ->method('getAffixes')
+ ->will($this->returnValue(['Git-'.$date.' (snap)', 'Git-'.$date.'
(Git)',]));
+ }
+
+ public function tearDown()
+ {
+ $this->cache->clear();
+ rmdir($this->cacheDir);
+ }
+
+ public function testVersions()
+ {
+ $versions = $this->generator->getVersions();
+
+ $this->assertInternalType('array', $versions);
+ $this->assertGreaterThan(5, count($versions));
+
+ $fixture = require __DIR__.'/../../fixtures/versions/versions.php';
+ $cached = require $this->cacheDir.'/versions.php';
+
+ $this->assertEquals($fixture[1], $cached[1]);
+ $this->assertContains('Next Major Version', $versions);
+ $this->assertContains('Irrelevant', $versions);
+ $this->assertContains('7.2.14RC1', $versions);
+ }
+}
diff --git a/tests/fixtures/versions/versions.php
b/tests/fixtures/versions/versions.php
new file mode 100644
index 0000000..6cae195
--- /dev/null
+++ b/tests/fixtures/versions/versions.php
@@ -0,0 +1,4 @@
+<?php return array (
+ 0 => 1545811329,
+ 1 => 'a:22:{i:0;s:8:"7.3.1RC1";i:1;s:5:"7.3.0";i:2;s:24:"7.3Git-2018-12-26
(snap)";i:3;s:23:"7.3Git-2018-12-26
(Git)";i:4;s:9:"7.2.14RC1";i:5;s:6:"7.2.13";i:6;s:24:"7.2Git-2018-12-26
(snap)";i:7;s:23:"7.2Git-2018-12-26
(Git)";i:8;s:6:"7.1.25";i:9;s:24:"7.1Git-2018-12-26
(snap)";i:10;s:23:"7.1Git-2018-12-26
(Git)";i:11;s:6:"7.0.33";i:12;s:24:"7.0Git-2018-12-26
(snap)";i:13;s:23:"7.0Git-2018-12-26
(Git)";i:14;s:6:"5.6.39";i:15;s:24:"5.6Git-2018-12-26
(snap)";i:16;s:23:"5.6Git-2018-12-26 (Git)";i:17;s:28:"master-Git-2018-12-26
(snap)";i:18;s:27:"master-Git-2018-12-26 (Git)";i:19;s:18:"Next Major
Version";i:20;s:18:"Next Minor Version";i:21;s:10:"Irrelevant";}',
+);
diff --git a/tests/mock/responses/dev-body.txt
b/tests/mock/responses/dev-body.txt
new file mode 100644
index 0000000..77697a6
--- /dev/null
+++ b/tests/mock/responses/dev-body.txt
@@ -0,0 +1 @@
+["5.6.40-dev","7.0.33-dev","7.1.25-dev","7.2.14-dev","7.2.14RC1","7.3.1-dev","7.3.1RC1"]
diff --git a/tests/mock/responses/stable-body.txt
b/tests/mock/responses/stable-body.txt
new file mode 100644
index 0000000..d4daa41
--- /dev/null
+++ b/tests/mock/responses/stable-body.txt
@@ -0,0 +1 @@
+{"5":{"5.6":{"announcement":true,"source":[{"filename":"php-5.6.39.tar.bz2","name":"PHP
5.6.39
(tar.bz2)","sha256":"b3db2345f50c010b01fe041b4e0f66c5aa28eb325135136f153e18da01583ad5","date":"06
Dec 2018"},{"filename":"php-5.6.39.tar.gz","name":"PHP 5.6.39
(tar.gz)","sha256":"127b122b7d6c7f3c211c0ffa554979370c3131196137404a51a391d8e2e9c7bb","date":"06
Dec 2018"},{"filename":"php-5.6.39.tar.xz","name":"PHP 5.6.39
(tar.xz)","sha256":"8147576001a832ff3d03cb2980caa2d6b584a10624f87ac459fcd3948c6e4a10","date":"06
Dec
2018"}],"version":"5.6.39"}},"7":{"7.0":{"announcement":true,"source":[{"filename":"php-7.0.33.tar.bz2","name":"PHP
7.0.33
(tar.bz2)","sha256":"4933ea74298a1ba046b0246fe3771415c84dfb878396201b56cb5333abe86f07","date":"06
Dec 2018"},{"filename":"php-7.0.33.tar.gz","name":"PHP 7.0.33
(tar.gz)","sha256":"d71a6ecb6b13dc53fed7532a7f8f949c4044806f067502f8fb6f9facbb40452a","date":"06
Dec 2018"},{"filename":"php-7.0.33.tar.xz","name":"PHP 7.0.33
(tar.xz)","sha256":"ab8c5be6e32b1f8d032909dedaaaa4bbb1a209e519abb01a52ce3914f9a13d96","date":"06
Dec
2018"}],"version":"7.0.33"},"7.1":{"announcement":true,"source":[{"filename":"php-7.1.25.tar.bz2","name":"PHP
7.1.25
(tar.bz2)","sha256":"002cdc880ac7cfaede2c389204d366108847db0f3ac72edf1ba95c0577f9aaac","date":"06
Dec 2018"},{"filename":"php-7.1.25.tar.gz","name":"PHP 7.1.25
(tar.gz)","sha256":"7dc40e202140e8b4fb3d992c15a68d98dc06b805e6b218497d260abbe51f5958","date":"06
Dec 2018"},{"filename":"php-7.1.25.tar.xz","name":"PHP 7.1.25
(tar.xz)","sha256":"0fd8dad1903cd0b2d615a1fe4209f99e53b7292403c8ffa1919c0f4dd1eada88","date":"06
Dec
2018"}],"version":"7.1.25"},"7.2":{"announcement":true,"source":[{"filename":"php-7.2.13.tar.bz2","name":"PHP
7.2.13
(tar.bz2)","sha256":"5b4a46fb76491bcd3eee1213773382e570f6ecf9b22d623b24e2822298b3e92d","date":"06
Dec 2018"},{"filename":"php-7.2.13.tar.gz","name":"PHP 7.2.13
(tar.gz)","sha256":"e563cee406b1ec96649c22ed2b35796cfe4e9aa9afa6eab6be4cf2fe5d724744","date":"06
Dec 2018"},{"filename":"php-7.2.13.tar.xz","name":"PHP 7.2.13
(tar.xz)","sha256":"14b0429abdb46b65c843e5882c9a8c46b31dfbf279c747293b8ab950c2644a4b","date":"06
Dec
2018"}],"version":"7.2.13"},"7.3":{"announcement":true,"source":[{"filename":"php-7.3.0.tar.bz2","name":"PHP
7.3.0
(tar.bz2)","sha256":"7a267daec9969a997c5c8028c350229646748e0fcc71e2f2dbb157ddcee87c67","date":"06
Dec 2018"},{"filename":"php-7.3.0.tar.gz","name":"PHP 7.3.0
(tar.gz)","sha256":"391bd0f91d9bdd01ab47ef9607bad8c65e35bc9bb098fb7777b2556e2c847b11","date":"06
Dec 2018"},{"filename":"php-7.3.0.tar.xz","name":"PHP 7.3.0
(tar.xz)","sha256":"7d195cad55af8b288c3919c67023a14ff870a73e3acc2165a6d17a4850a560b5","date":"06
Dec 2018"}],"version":"7.3.0"}}}
diff --git a/www/report.php b/www/report.php
index b5e4ebe..9a7b61b 100644
--- a/www/report.php
+++ b/www/report.php
@@ -2,9 +2,12 @@
use App\Repository\PackageRepository;
use App\Repository\ReasonRepository;
+use App\Utils\Cache;
use App\Utils\Captcha;
use App\Utils\PatchTracker;
use App\Utils\Uploader;
+use App\Utils\Versions\Client;
+use App\Utils\Versions\Generator;
// Obtain common includes
require_once '../include/prepend.php';
@@ -22,7 +25,11 @@ $pseudo_pkgs =
$packageRepository->findEnabled($_GET['project'] ?? '');
// Authenticate
bugs_authenticate($user, $pw, $logged_in, $user_flags);
-require "{$ROOT_DIR}/include/php_versions.php";
+$versionsClient = new Client();
+$cacheDir = (defined('DEVBOX') && true === DEVBOX) ? __DIR__.'/../var/cache' :
'/tmp';
+$cache = new Cache($cacheDir);
+$versionsGenerator = new Generator($versionsClient, $cache);
+$versions = $versionsGenerator->getVersions();
// captcha is not necessary if the user is logged in
if (!$logged_in) {
--
PHP Webmaster List Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php