diff --git a/bin/bumpRelease b/bin/bumpRelease
index f03c2c6da9..50ecf6bedc 100755
--- a/bin/bumpRelease
+++ b/bin/bumpRelease
@@ -1,21 +1,24 @@
#!/usr/bin/env php
[
+ 'features' => [
+ [
+ 'title' => 'URI Extension',
+ 'about' => 'PHP 8.5 adds a built-in URI extension to parse, normalize, and handle URLs following RFC 3986 and WHATWG URL standards.',
+ ],
+ [
+ 'title' => 'Pipe Operator',
+ 'about' => 'The |> operator enables chaining callables left-to-right, passing values smoothly through multiple functions without intermediary variables.',
+ ],
+ [
+ 'title' => 'Clone With',
+ 'about' => 'Clone objects and update properties with the new clone() syntax, making the "with-er" pattern simple for readonly classes.',
+ ],
+ [
+ 'title' => '#[\NoDiscard] Attribute',
+ 'about' => 'The #[\NoDiscard] attribute warns when a return value isn’t used, helping prevent mistakes and improving overall API safety.',
+ ],
+ [
+ 'title' => 'Closures and First-Class Callables in Constant Expressions',
+ 'about' => 'Static closures and first-class callables can now be used in constant expressions, such as attribute parameters.',
+ ],
+ [
+ 'title' => 'Persistent cURL Share Handles',
+ 'about' => 'Handles can now be persisted across multiple PHP requests, avoiding the cost of repeated connection initialization to the same hosts.',
+ ],
+ ],
+ ],
+ '8.4' => [
+ 'support_label' => 'Supported',
+ 'features' => [
+ [
+ 'title' => 'Property Hooks',
+ 'short' => 'Property Hooks allow intercepting properties',
+ ],
+ [
+ 'title' => 'Asymmetric Property Visibility',
+ 'short' => 'Asymmetric Visibility for get and set',
+ ],
+ [
+ 'title' => '#[Deprecated] Attribute',
+ 'short' => '#[Deprecated] attribute signals removal intent',
+ ],
+ [
+ 'title' => 'Additional Array Functions',
+ 'short' => 'New array lookup and query options',
+ ],
+ ],
+ ],
+ '8.3' => [
+ 'support_label' => 'Security Support',
+ 'features' => [
+ [
+ 'title' => 'Typed Class Constants',
+ 'short' => 'Class constants can now be typed',
+ ],
+ [
+ 'title' => 'Dynamic Class Constants',
+ 'about' => 'Class constants can now be accessed via dynamic calls',
+ ],
+ [
+ 'title' => 'Readonly Deep Cloning',
+ 'short' => 'Enhanced deep cloning of readonly instances',
+ ],
+ [
+ 'title' => 'Randomizer Improvements',
+ 'short' => 'Generate random strings from provided character sets',
+ ],
+ ],
+ ],
+ '8.2' => [
+ 'support_label' => 'Security Support',
+ 'features' => [
+ [
+ 'title' => 'Readonly classes',
+ 'short' => 'Entire classes can now be marked Readonly',
+ ],
+ [
+ 'title' => 'Disjunction Normal Form Types',
+ 'short' => 'Improved type support with Disjunction Normal Forms',
+ ],
+ [
+ 'title' => 'Improved Standalone Types',
+ 'short' => 'Null, true and false are now usable as types',
+ ],
+ ],
+ ],
+
+ /*
+ * The rest of these were AI generated
+ */
+
+ '8.1' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Enums',
+ 'short' => 'Native support for Enumerations',
+ ],
+ [
+ 'title' => 'Fibers',
+ 'short' => 'Core support for asynchronous programming',
+ ],
+ [
+ 'title' => 'Readonly Properties',
+ 'short' => 'Class properties can be permanently marked readonly',
+ ],
+ [
+ 'title' => 'First-class Callable Syntax',
+ 'short' => 'Clean syntax for creating closures from callables',
+ ],
+ ],
+ ],
+ '8.0' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Named Arguments',
+ 'short' => 'Pass arguments to functions based on parameter names',
+ ],
+ [
+ 'title' => 'Attributes',
+ 'short' => 'Native syntax for structured metadata (annotations)',
+ ],
+ [
+ 'title' => 'Constructor Property Promotion',
+ 'short' => 'Shorthand syntax for defining and initializing properties',
+ ],
+ [
+ 'title' => 'Match Expression',
+ 'short' => 'Strict, expression-based alternative to switch statements',
+ ],
+ ],
+ ],
+ '7.4' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Typed Properties',
+ 'short' => 'Class properties fully support type declarations',
+ ],
+ [
+ 'title' => 'Arrow Functions',
+ 'short' => 'Concise syntax for simple one-liner closures',
+ ],
+ [
+ 'title' => 'Null Coalescing Assignment',
+ 'short' => 'Assign values quickly using the ??= operator',
+ ],
+ [
+ 'title' => 'Spread Operator in Arrays',
+ 'short' => 'Unpack arrays directly inside other arrays using ...',
+ ],
+ ],
+ ],
+ '7.3' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Flexible Heredoc/Nowdoc',
+ 'short' => 'Improved formatting and indentation parsing for multi-line strings',
+ ],
+ [
+ 'title' => 'Trailing Commas',
+ 'short' => 'Allow trailing commas in function calls',
+ ],
+ [
+ 'title' => 'Array Destructuring References',
+ 'short' => 'List destructuring supports assignment by reference',
+ ],
+ [
+ 'title' => 'is_countable()',
+ 'short' => 'New function to safely verify if a variable is countable',
+ ],
+ ],
+ ],
+ '7.2' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Object Typehint',
+ 'short' => 'Use \'object\' as a formal type declaration',
+ ],
+ [
+ 'title' => 'Argon2 Hashing',
+ 'short' => 'Native support for the Argon2 password hashing algorithm',
+ ],
+ [
+ 'title' => 'Libsodium Integration',
+ 'short' => 'Modern cryptography via the core Sodium extension',
+ ],
+ [
+ 'title' => 'Abstract Method Overriding',
+ 'short' => 'Traits can now be overridden by abstract methods',
+ ],
+ ],
+ ],
+ '7.1' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Nullable Types',
+ 'short' => 'Prepend types with a question mark to allow nulls',
+ ],
+ [
+ 'title' => 'Void Return Type',
+ 'short' => 'Functions can explicitly declare a \'void\' return',
+ ],
+ [
+ 'title' => 'Iterable Pseudo-type',
+ 'short' => 'Accept arrays or Traversable objects interchangeably',
+ ],
+ [
+ 'title' => 'Multi-catch Exceptions',
+ 'short' => 'Catch multiple exception types within a single block',
+ ],
+ ],
+ ],
+ '7.0' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Scalar Type Declarations',
+ 'short' => 'Type hinting for int, float, string, and bool',
+ ],
+ [
+ 'title' => 'Return Type Declarations',
+ 'short' => 'Specify the strict return type of a function',
+ ],
+ [
+ 'title' => 'Null Coalescing Operator',
+ 'short' => 'Simplify isset checks with the ?? operator',
+ ],
+ [
+ 'title' => 'Spaceship Operator',
+ 'short' => 'Combined comparison using the <=> operator',
+ ],
+ ],
+ ],
+ '5.6' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Variadic Functions',
+ 'short' => 'Accept variable-length argument lists using ...',
+ ],
+ [
+ 'title' => 'Argument Unpacking',
+ 'short' => 'Unpack arrays dynamically into function arguments',
+ ],
+ [
+ 'title' => 'Constant Scalar Expressions',
+ 'short' => 'Use basic math and expressions when defining constants',
+ ],
+ [
+ 'title' => 'Exponentiation Operator',
+ 'short' => 'Calculate powers easily using the ** operator',
+ ],
+ ],
+ ],
+ '5.5' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Generators',
+ 'short' => 'Create simple iterators using the \'yield\' keyword',
+ ],
+ [
+ 'title' => 'Finally Keyword',
+ 'short' => 'Execute code unconditionally after try/catch blocks',
+ ],
+ [
+ 'title' => '::class Resolution',
+ 'short' => 'Fetch fully qualified class names as strings',
+ ],
+ [
+ 'title' => 'empty() Expressions',
+ 'short' => 'The empty() construct now accepts arbitrary expressions',
+ ],
+ ],
+ ],
+ '5.4' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Traits',
+ 'short' => 'Enable horizontal code reuse across independent classes',
+ ],
+ [
+ 'title' => 'Short Array Syntax',
+ 'short' => 'Define arrays cleanly using the [] syntax',
+ ],
+ [
+ 'title' => 'Built-in Web Server',
+ 'short' => 'Integrated CLI web server for local development',
+ ],
+ [
+ 'title' => 'Closure $this',
+ 'short' => 'Anonymous functions can automatically access object scope',
+ ],
+ ],
+ ],
+ '5.3' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Namespaces',
+ 'short' => 'Organize code and prevent naming collisions',
+ ],
+ [
+ 'title' => 'Late Static Binding',
+ 'short' => 'Reference the called class context using static::',
+ ],
+ [
+ 'title' => 'Closures',
+ 'short' => 'Support for anonymous functions and inline callbacks',
+ ],
+ [
+ 'title' => 'Ternary Shortcut',
+ 'short' => 'Omit the middle expression using the ?: operator',
+ ],
+ ],
+ ],
+ '5.2' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'JSON Support',
+ 'short' => 'Native json_encode and json_decode functions added',
+ ],
+ [
+ 'title' => 'Filter Extension',
+ 'short' => 'Built-in data validation and sanitization filters',
+ ],
+ [
+ 'title' => 'Zip Extension',
+ 'short' => 'Native support for creating and reading ZIP archives',
+ ],
+ [
+ 'title' => 'DateTime Extension',
+ 'short' => 'Introduction of the object-oriented DateTime class',
+ ],
+ ],
+ ],
+ '5.1' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'PDO Extension',
+ 'short' => 'Standardized, lightweight interface for database access',
+ ],
+ [
+ 'title' => 'Performance Upgrades',
+ 'short' => 'Significant execution speed improvements over 5.0',
+ ],
+ [
+ 'title' => 'Magic Methods',
+ 'short' => 'Added support for __isset() and __unset()',
+ ],
+ [
+ 'title' => 'Type Hinting for Arrays',
+ 'short' => 'Allow \'array\' as an explicit parameter type hint',
+ ],
+ ],
+ ],
+ '5.0' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Zend Engine 2',
+ 'short' => 'A completely rewritten core engine for better performance',
+ ],
+ [
+ 'title' => 'Robust Object Model',
+ 'short' => 'Introduction of true OOP with visibility (public/protected/private)',
+ ],
+ [
+ 'title' => 'Exceptions',
+ 'short' => 'Standardized try/catch error handling model',
+ ],
+ [
+ 'title' => 'SimpleXML',
+ 'short' => 'An easy-to-use extension for parsing XML structures',
+ ],
+ ],
+ ],
+ '4.4' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Reference Memory Fixes',
+ 'short' => 'Fixed major memory corruption issues related to references',
+ ],
+ [
+ 'title' => 'max_input_nesting_level',
+ 'short' => 'Added an INI directive to limit the nesting level of input variables',
+ ],
+ [
+ 'title' => 'Stream-based Hashing',
+ 'short' => 'File hashing functions now use streams instead of low-level IO',
+ ],
+ [
+ 'title' => 'SORT_LOCALE_STRING',
+ 'short' => 'Added flag to sort arrays based on the current locale',
+ ],
+ ],
+ ],
+ '4.3' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Command Line Interface',
+ 'short' => 'Introduced a separate CLI SAPI for developing shell applications',
+ ],
+ [
+ 'title' => 'Streams API',
+ 'short' => 'Unified approach to handling files, pipes, sockets, and I/O resources',
+ ],
+ [
+ 'title' => 'Bundled GD Library',
+ 'short' => 'The GD image manipulation library is now bundled by default',
+ ],
+ [
+ 'title' => 'New Build System',
+ 'short' => 'A more portable and less resource-consuming build process',
+ ],
+ ],
+ ],
+ '4.2' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'register_globals Off',
+ 'short' => 'External variables are no longer registered in the global scope by default',
+ ],
+ [
+ 'title' => 'Sockets Overhaul',
+ 'short' => 'Major overhaul of the sockets extension for better reliability',
+ ],
+ [
+ 'title' => 'File Upload Performance',
+ 'short' => 'Highly improved performance and handling of file uploads',
+ ],
+ [
+ 'title' => 'Apache 2 Support',
+ 'short' => 'Introduced experimental support for the Apache 2 web server',
+ ],
+ ],
+ ],
+ '4.1' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Superglobals',
+ 'short' => 'Introduced autoglobal arrays like $_GET, $_POST, and $_SESSION',
+ ],
+ [
+ 'title' => 'Windows Performance',
+ 'short' => 'Revolutionary performance and stability improvements under Windows',
+ ],
+ [
+ 'title' => 'Output Compression',
+ 'short' => 'Added turn-key output compression support',
+ ],
+ [
+ 'title' => 'Extension Versioning',
+ 'short' => 'Added infrastructure to support version numbers for different extensions',
+ ],
+ ],
+ ],
+ '4.0' => [
+ 'support_label' => 'End of Life',
+ 'features' => [
+ [
+ 'title' => 'Zend Engine',
+ 'short' => 'A new, highly optimized two-stage parse and execute engine',
+ ],
+ [
+ 'title' => 'Native Sessions',
+ 'short' => 'Built-in support for HTTP session management',
+ ],
+ [
+ 'title' => 'Output Buffering',
+ 'short' => 'Ability to buffer output before sending it to the browser',
+ ],
+ [
+ 'title' => 'Enhanced OOP',
+ 'short' => 'More comprehensive object-oriented programming support over PHP 3',
+ ],
+ ],
+ ],
+];
diff --git a/include/branch-overrides.inc b/include/branch-overrides.inc
new file mode 100644
index 0000000000..519facb955
--- /dev/null
+++ b/include/branch-overrides.inc
@@ -0,0 +1,33 @@
+ [
+ 'security' => '2000-10-20',
+ ],
+ '5.3' => [
+ 'stable' => '2013-07-11',
+ 'security' => '2014-08-14',
+ ],
+ '5.4' => [
+ 'stable' => '2014-09-14',
+ 'security' => '2015-09-03',
+ ],
+ '5.5' => [
+ 'stable' => '2015-07-10',
+ 'security' => '2016-07-21',
+ ],
+ '5.6' => [
+ 'stable' => '2017-01-19',
+ 'security' => '2018-12-31',
+ ],
+ '7.0' => [
+ 'stable' => '2018-01-04',
+ 'security' => '2019-01-10',
+ ],
+ '8.4' => [
+ 'date' => '2024-11-21',
+ ],
+];
diff --git a/include/branches.inc b/include/branches.inc
index deb1f79841..2111319261 100644
--- a/include/branches.inc
+++ b/include/branches.inc
@@ -1,5 +1,7 @@
[
- 'security' => '2000-10-20',
- ],
- '5.3' => [
- 'stable' => '2013-07-11',
- 'security' => '2014-08-14',
- ],
- '5.4' => [
- 'stable' => '2014-09-14',
- 'security' => '2015-09-03',
- ],
- '5.5' => [
- 'stable' => '2015-07-10',
- 'security' => '2016-07-21',
- ],
- '5.6' => [
- 'stable' => '2017-01-19',
- 'security' => '2018-12-31',
- ],
- '7.0' => [
- 'stable' => '2018-01-04',
- 'security' => '2019-01-10',
- ],
- '8.4' => [
- 'date' => '2024-11-21',
- ],
-];
+$BRANCHES = require __DIR__ . '/branch-overrides.inc';
/* Time to keep EOLed branches in the array returned by get_active_branches(),
* which is used on the front page download links and the supported versions
@@ -98,6 +70,7 @@ function version_number_to_branch(string $version): ?string {
return null;
}
+#[Deprecated('Use Branches::get_all_branches()')]
function get_all_branches() {
$branches = [];
@@ -135,7 +108,8 @@ function get_all_branches() {
return $branches;
}
-function get_active_branches($include_recent_eols = true) {
+#[Deprecated('Use Branches::active()')]
+function get_active_branches(bool $include_recent_eols = true) {
$branches = [];
$now = new DateTime();
@@ -170,6 +144,7 @@ function get_active_branches($include_recent_eols = true) {
/* If you provide an array to $always_include, note that the version numbers
* must be in $RELEASES _and_ must be the full version number, not the branch:
* ie provide array('5.3.29'), not array('5.3'). */
+#[Deprecated('Use Branches::eol()')]
function get_eol_branches($always_include = null) {
$always_include = $always_include ?: [];
$branches = [];
@@ -246,6 +221,7 @@ function get_eol_branches($always_include = null) {
* MAJOR.MINOR.REVISION (the REVISION will be ignored if provided). This will
* return either null (if no release exists on the given branch), or the usual
* version metadata from $RELEASES for a single release. */
+#[Deprecated('Use Branches::getInitialRelease')]
function get_initial_release($branch) {
$branch = version_number_to_branch($branch);
if (!$branch) {
@@ -274,6 +250,7 @@ function get_initial_release($branch) {
return null;
}
+#[Deprecated('Use Branches::getFinalRelease')]
function get_final_release($branch) {
$branch = version_number_to_branch($branch);
if (!$branch) {
@@ -305,6 +282,7 @@ function get_final_release($branch) {
return null;
}
+#[Deprecated('Use Branches::getBranchBugsEOLDate')]
function get_branch_bug_eol_date($branch): ?DateTime
{
if (isset($GLOBALS['BRANCHES'][$branch]['stable'])) {
@@ -324,6 +302,7 @@ function get_branch_bug_eol_date($branch): ?DateTime
return $date?->setDate($date->format('Y'), 12, 31);
}
+#[Deprecated('Use Branches::getBranchSecurityEOLDate')]
function get_branch_security_eol_date($branch): ?DateTime
{
if (isset($GLOBALS['BRANCHES'][$branch]['security'])) {
@@ -351,6 +330,7 @@ function get_branch_security_eol_date($branch): ?DateTime
return $date?->setDate($date->format('Y'), 12, 31);
}
+#[Deprecated('Use Branches::getBranchReleaseDate')]
function get_branch_release_date($branch): ?DateTime
{
$initial = get_initial_release($branch);
@@ -358,6 +338,7 @@ function get_branch_release_date($branch): ?DateTime
return isset($initial['date']) ? new DateTime($initial['date']) : null;
}
+#[Deprecated('Use Branches::getBranchSupportState')]
function get_branch_support_state($branch) {
$initial = get_branch_release_date($branch);
$bug = get_branch_bug_eol_date($branch);
@@ -399,7 +380,7 @@ function compare_version(array $arrayA, string $versionB)
return 0;
}
-function version_array(string $version, ?int $length = null)
+function version_array(string $version, ?int $length = null): mixed
{
$versionArray = array_map(
'intval',
@@ -419,6 +400,7 @@ function version_array(string $version, ?int $length = null)
return $versionArray;
}
+#[Deprecated('Use Branches::getCurrentReleaseForBranch')]
function get_current_release_for_branch(int $major, ?int $minor): ?string {
global $RELEASES, $OLDRELEASES;
@@ -441,3 +423,80 @@ function get_current_release_for_branch(int $major, ?int $minor): ?string {
return null;
}
+
+
+// Get latest release version and info.
+/**
+ * @return array{mixed,mixed}
+ */
+function release_get_latest(): array {
+ $RELEASES = Branches::getReleaseData();
+
+ $version = '0.0.0';
+ $current = null;
+ foreach ($RELEASES as $versions) {
+ foreach ($versions as $ver => $info) {
+ if (version_compare($ver, $version) > 0) {
+ $version = $ver;
+ $current = $info;
+ }
+ }
+ }
+
+ return [$version, $current];
+}
+
+function show_source_releases(): void
+{
+ $RELEASES = Branches::getReleaseData();
+
+ $SHOW_COUNT = 4;
+
+ $current_uri = htmlspecialchars($_SERVER['REQUEST_URI'], ENT_QUOTES, 'UTF-8');
+
+ $i = 0; foreach ($RELEASES as $MAJOR => $major_releases): /* major releases loop start */
+ $releases = array_slice($major_releases, 0, $SHOW_COUNT);
+ ?>
+
+ $a): ?>
+
+
+
+