diff --git a/downloads-get-instructions.php b/downloads-get-instructions.php new file mode 100644 index 0000000000..aabc617978 --- /dev/null +++ b/downloads-get-instructions.php @@ -0,0 +1,83 @@ + '', + 'usage' => '', + 'version' => '', + ]; +} + +if ($options['os'] === 'windows') { + if ($options['osvariant'] === 'windows-wsl-debian') { + $options['os'] = 'linux'; + $options['osvariant'] = 'linux-debian'; + } + if ($options['osvariant'] === 'windows-wsl-ubuntu') { + $options['os'] = 'linux'; + $options['osvariant'] = 'linux-ubuntu'; + } +} +if ($options['os'] === 'osx' || $options['os'] === 'windows') { + if ($options['version'] === 'default') { + $options['version'] = $latestPhpVersion; + } +} + +if (in_array($options['usage'], ['fw-drupal', 'fw-laravel', 'fw-symfony', 'fw-wordpress'])) { + $file = "{$options['usage']}"; + $options['os'] = null; +} + +$multiversion = false; + +if (array_key_exists('multiversion', $options)) { + $multiversion = $options['multiversion'] === 'Y'; +} + +$source = false; + +if (array_key_exists('source', $options)) { + if ($options['source'] === 'Y') { + $source = $options['source'] === 'Y'; + } +} + +switch ($options['os']) { + case 'linux': + $defaultOrCommunity = ($options['version'] !== 'default' || $multiversion) ? 'community' : 'default'; + if ($defaultOrCommunity === 'community' && $options['version'] == 'default') { + $options['version'] = $latestPhpVersion; + } + $file = "{$options['osvariant']}-{$options['usage']}-{$defaultOrCommunity}"; + break; + case 'osx': + case 'windows': + $file = "{$options['osvariant']}"; + break; +} + +if ($source) { + $file = "{$options['os']}-source"; +} + +$version = $options['version']; +$versionNoDot = str_replace('.', '', $version); + +if (file_exists(__DIR__ . "/include/download-instructions/{$file}.php")) { + include __DIR__ . "/include/download-instructions/{$file}.php"; + if ($source) { + return false; + } + return true; +} else { +?> +

+ There are no instructions yet. Try using the generic installation from source. +

+ diff --git a/downloads.php b/downloads.php index 5468da840f..ae8ba587d4 100644 --- a/downloads.php +++ b/downloads.php @@ -7,8 +7,6 @@ // Try to make this page non-cached header_nocache(); -$SHOW_COUNT = 4; - $SIDEBAR_DATA = '
Supported Versions @@ -18,6 +16,7 @@
+

Source Tarballs

Documentation Download

PHP Logos

@@ -37,14 +36,164 @@ ], ], "current" => "downloads", + "css" => [ + "prism.css", + "code-syntax.css", + ], + "js_files" => [ + "js/ext/prism.js", + ], ], ); + +function option(string $value, string $desc, $attributes = []): string +{ + return ''; +} + +$usage = [ + 'web' => 'Web Development', + 'cli' => 'CLI/Library Development', + 'fw-drupal' => 'Drupal Development', + 'fw-laravel' => 'Laravel Development', + 'fw-symfony' => 'Symfony Development', + 'fw-wordpress' => 'WordPress Development', +]; + +$os = [ + 'linux' => [ + 'name' => 'Linux', + 'variants' => [ + 'linux-debian' => 'Debian', + 'linux-fedora' => 'Fedora', + 'linux-redhat' => 'RedHat', + 'linux-ubuntu' => 'Ubuntu', + ], + ], + 'osx' => [ + 'name' => 'macOS', + 'variants' => [ + 'osx-homebrew' => 'Homebrew/Brew', + 'osx-homebrew-php' => 'Homebrew/Homebrew-PHP', + 'osx-macports' => 'MacPorts', + ], + ], + 'windows' => [ + 'name' => 'Windows', + 'variants' => [ + 'windows-native' => 'Windows Native Build', + 'windows-chocolatey' => 'Windows with Chocolatey', + 'windows-scoop' => 'Windows with Scoop', + 'windows-wsl-debian' => 'Windows with WSL/Debian', + 'windows-wsl-ubuntu' => 'Windows with WSL/Ubuntu', + ], + ], +]; + +$versions = [ + '8.4' => 'version 8.4', + '8.3' => 'version 8.3', + '8.2' => 'version 8.2', + '8.1' => 'version 8.1', + 'default' => 'OS default version', +]; + +$defaults = [ + 'os' => 'linux', + 'version' => 'default', + 'usage' => 'web', +]; + +$options = array_merge($defaults, $_GET); +if (!array_key_exists('osvariant', $options) || !array_key_exists($options['osvariant'], $os[$options['os']]['variants'])) { + $options['osvariant'] = array_key_first($os[$options['os']]['variants']); +} ?>

Downloads & Installation Instructions

+
+
+ I want to use PHP for + . +
+ +
+ I work with + + + + + , + and use + +
+ + + + + + +
+ +

Instructions

+
+ +
+ + + +

Source Code

+ + +
+

GPG Keys

- Installing PHP is covered - thoroughly in the PHP documentation. +The releases are tagged and signed in the PHP Git Repository. +The following official GnuPG keys of the current PHP Release Manager can be used +to verify the tags: +

+ + + +

+ + A full list of GPG keys used for current and older releases is also + available. +

Binaries

@@ -65,67 +214,17 @@

-

Source Code

- $major_releases): /* major releases loop start */ - $releases = array_slice($major_releases, 0, $SHOW_COUNT); -?> - - $a): ?> - - - -

- - PHP - (Changelog) -

-
- - - - GPG Keys for PHP -
- - - -
-

GPG Keys

-

-The releases are tagged and signed in the PHP Git Repository. -The following official GnuPG keys of the current PHP Release Manager can be used -to verify the tags: -

+ - + $SIDEBAR_DATA]); diff --git a/include/download-instructions/fw-drupal.php b/include/download-instructions/fw-drupal.php new file mode 100644 index 0000000000..20ff7332ae --- /dev/null +++ b/include/download-instructions/fw-drupal.php @@ -0,0 +1,6 @@ +

+Instructions for installing PHP for Drupal development can be found on: +

+

https://www.drupal.org/docs/getting-started/installing-drupal +

diff --git a/include/download-instructions/fw-laravel.php b/include/download-instructions/fw-laravel.php new file mode 100644 index 0000000000..62c4282b6a --- /dev/null +++ b/include/download-instructions/fw-laravel.php @@ -0,0 +1,6 @@ +

+Instructions for installing PHP for Laravel development can be found on: +

+

https://laravel.com/docs/12.x/installation#installing-php +

diff --git a/include/download-instructions/fw-symfony.php b/include/download-instructions/fw-symfony.php new file mode 100644 index 0000000000..f03259972f --- /dev/null +++ b/include/download-instructions/fw-symfony.php @@ -0,0 +1,6 @@ +

+Instructions for installing PHP for Symfony development can be found on: +

+

https://symfony.com/doc/current/setup.html +

diff --git a/include/download-instructions/fw-wordpress.php b/include/download-instructions/fw-wordpress.php new file mode 100644 index 0000000000..1fd289f75d --- /dev/null +++ b/include/download-instructions/fw-wordpress.php @@ -0,0 +1,6 @@ +

+Instructions for installing PHP for WordPress development can be found on: +

+

https://wordpress.org/support/article/how-to-install-wordpress/ +

diff --git a/include/download-instructions/linux-debian-cli-community.php b/include/download-instructions/linux-debian-cli-community.php new file mode 100644 index 0000000000..cc1595689a --- /dev/null +++ b/include/download-instructions/linux-debian-cli-community.php @@ -0,0 +1,15 @@ +

+On the command line, run the following commands: +

+

+# Add the packages.sury.org/php repository.
+sudo apt-get update
+sudo apt-get install -y lsb-release ca-certificates apt-transport-https curl
+sudo curl -sSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
+sudo dpkg -i /tmp/debsuryorg-archive-keyring.deb
+sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/debsuryorg-archive-keyring.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'
+sudo apt-get update
+
+# Install PHP.
+sudo apt-get install -y php
+
diff --git a/include/download-instructions/linux-debian-cli-default.php b/include/download-instructions/linux-debian-cli-default.php new file mode 100644 index 0000000000..534da00616 --- /dev/null +++ b/include/download-instructions/linux-debian-cli-default.php @@ -0,0 +1,10 @@ +

+On the command line, run the following commands: +

+

+# Update the package lists.
+sudo apt update
+
+# Install PHP.
+sudo apt install -y php
+
diff --git a/include/download-instructions/linux-debian-web-community.php b/include/download-instructions/linux-debian-web-community.php new file mode 120000 index 0000000000..b21d40f00c --- /dev/null +++ b/include/download-instructions/linux-debian-web-community.php @@ -0,0 +1 @@ +linux-debian-cli-community.php \ No newline at end of file diff --git a/include/download-instructions/linux-debian-web-default.php b/include/download-instructions/linux-debian-web-default.php new file mode 120000 index 0000000000..0017979f66 --- /dev/null +++ b/include/download-instructions/linux-debian-web-default.php @@ -0,0 +1 @@ +linux-debian-cli-default.php \ No newline at end of file diff --git a/include/download-instructions/linux-fedora-cli-community.php b/include/download-instructions/linux-fedora-cli-community.php new file mode 100644 index 0000000000..3f414122c5 --- /dev/null +++ b/include/download-instructions/linux-fedora-cli-community.php @@ -0,0 +1,13 @@ +

+On the command line, run the following commands: +

+

+# Add the Remi's RPM repository.
+sudo dnf install -y dnf-plugins-core
+sudo dnf install -y https://rpms.remirepo.net/fedora/remi-release-$(rpm -E %fedora).rpm
+sudo dnf module reset php -y
+sudo dnf module enable php:remi- -y
+
+# Install PHP.
+sudo dnf install -y php
+
diff --git a/include/download-instructions/linux-fedora-cli-default.php b/include/download-instructions/linux-fedora-cli-default.php new file mode 100644 index 0000000000..61d64d3c50 --- /dev/null +++ b/include/download-instructions/linux-fedora-cli-default.php @@ -0,0 +1,7 @@ +

+On the command line, run the following commands: +

+

+# Install PHP.
+sudo dnf install -y php
+
diff --git a/include/download-instructions/linux-fedora-web-community.php b/include/download-instructions/linux-fedora-web-community.php new file mode 120000 index 0000000000..96f87a049c --- /dev/null +++ b/include/download-instructions/linux-fedora-web-community.php @@ -0,0 +1 @@ +linux-fedora-cli-community.php \ No newline at end of file diff --git a/include/download-instructions/linux-fedora-web-default.php b/include/download-instructions/linux-fedora-web-default.php new file mode 120000 index 0000000000..83c945fbe5 --- /dev/null +++ b/include/download-instructions/linux-fedora-web-default.php @@ -0,0 +1 @@ +linux-fedora-cli-default.php \ No newline at end of file diff --git a/include/download-instructions/linux-redhat-cli-community.php b/include/download-instructions/linux-redhat-cli-community.php new file mode 100644 index 0000000000..7a647a04ef --- /dev/null +++ b/include/download-instructions/linux-redhat-cli-community.php @@ -0,0 +1,15 @@ +

+On the command line, run the following commands: +

+

+# Add the Remi's RPM repository.
+sudo subscription-manager repos --enable codeready-builder-for-rhel-$(rpm -E %rhel)-$(arch)-rpms
+sudo dnf install -y dnf-plugins-core
+sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-$(rpm -E %rhel).noarch.rpm
+sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-$(rpm -E %rhel).rpm
+sudo dnf module reset php -y
+sudo dnf module enable php:remi- -y
+
+# Install PHP.
+sudo dnf install -y php
+
diff --git a/include/download-instructions/linux-redhat-cli-default.php b/include/download-instructions/linux-redhat-cli-default.php new file mode 100644 index 0000000000..61d64d3c50 --- /dev/null +++ b/include/download-instructions/linux-redhat-cli-default.php @@ -0,0 +1,7 @@ +

+On the command line, run the following commands: +

+

+# Install PHP.
+sudo dnf install -y php
+
diff --git a/include/download-instructions/linux-redhat-web-community.php b/include/download-instructions/linux-redhat-web-community.php new file mode 120000 index 0000000000..b41bc5d464 --- /dev/null +++ b/include/download-instructions/linux-redhat-web-community.php @@ -0,0 +1 @@ +linux-redhat-cli-community.php \ No newline at end of file diff --git a/include/download-instructions/linux-redhat-web-default.php b/include/download-instructions/linux-redhat-web-default.php new file mode 120000 index 0000000000..38d6e97f7b --- /dev/null +++ b/include/download-instructions/linux-redhat-web-default.php @@ -0,0 +1 @@ +linux-redhat-cli-default.php \ No newline at end of file diff --git a/include/download-instructions/linux-source.php b/include/download-instructions/linux-source.php new file mode 100644 index 0000000000..47437b2c77 --- /dev/null +++ b/include/download-instructions/linux-source.php @@ -0,0 +1,4 @@ +

+ The instructions for compiling from source + on Linux are described in the PHP manual. +

diff --git a/include/download-instructions/linux-ubuntu-cli-community.php b/include/download-instructions/linux-ubuntu-cli-community.php new file mode 100644 index 0000000000..100666c8ea --- /dev/null +++ b/include/download-instructions/linux-ubuntu-cli-community.php @@ -0,0 +1,13 @@ +

+On the command line, run the following commands: +

+

+# Add the ondrej/php repository.
+sudo apt update
+sudo apt install -y software-properties-common
+sudo LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php -y
+sudo apt update
+
+# Install PHP.
+sudo apt install -y php
+
diff --git a/include/download-instructions/linux-ubuntu-cli-default.php b/include/download-instructions/linux-ubuntu-cli-default.php new file mode 100644 index 0000000000..534da00616 --- /dev/null +++ b/include/download-instructions/linux-ubuntu-cli-default.php @@ -0,0 +1,10 @@ +

+On the command line, run the following commands: +

+

+# Update the package lists.
+sudo apt update
+
+# Install PHP.
+sudo apt install -y php
+
diff --git a/include/download-instructions/linux-ubuntu-web-community.php b/include/download-instructions/linux-ubuntu-web-community.php new file mode 120000 index 0000000000..cbcc4a6ff3 --- /dev/null +++ b/include/download-instructions/linux-ubuntu-web-community.php @@ -0,0 +1 @@ +linux-ubuntu-cli-community.php \ No newline at end of file diff --git a/include/download-instructions/linux-ubuntu-web-default.php b/include/download-instructions/linux-ubuntu-web-default.php new file mode 120000 index 0000000000..c4a0004521 --- /dev/null +++ b/include/download-instructions/linux-ubuntu-web-default.php @@ -0,0 +1 @@ +linux-ubuntu-cli-default.php \ No newline at end of file diff --git a/include/download-instructions/osx-homebrew-php.php b/include/download-instructions/osx-homebrew-php.php new file mode 100644 index 0000000000..5fd20fc401 --- /dev/null +++ b/include/download-instructions/osx-homebrew-php.php @@ -0,0 +1,12 @@ +

+On the command line, run the following commands: +

+

+# Download and install Homebrew.
+curl -o- https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh | bash
+
+# Install and link PHP.
+brew install shivammathur/php/php@
+
+brew link --force --overwrite php@
+
diff --git a/include/download-instructions/osx-homebrew.php b/include/download-instructions/osx-homebrew.php new file mode 100644 index 0000000000..bc2f033cac --- /dev/null +++ b/include/download-instructions/osx-homebrew.php @@ -0,0 +1,12 @@ +

+On the command line, run the following commands: +

+

+# Download and install Homebrew.
+curl -o- https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh | bash
+
+# Install and link PHP.
+brew install php@
+
+brew link --force --overwrite php@
+
diff --git a/include/download-instructions/osx-macports.php b/include/download-instructions/osx-macports.php new file mode 100644 index 0000000000..057c940465 --- /dev/null +++ b/include/download-instructions/osx-macports.php @@ -0,0 +1,7 @@ +

+On the command line, run the following commands: +

+

+# Please refer to https://guide.macports.org/chunked/installing.macports.html for installing MacPorts.
+sudo port install php
+
diff --git a/include/download-instructions/osx-source.php b/include/download-instructions/osx-source.php new file mode 100644 index 0000000000..aa81b80171 --- /dev/null +++ b/include/download-instructions/osx-source.php @@ -0,0 +1,4 @@ +

+ The instructions for compiling from source + on macOS are described in the PHP manual. +

diff --git a/include/download-instructions/windows-chocolatey.php b/include/download-instructions/windows-chocolatey.php new file mode 100644 index 0000000000..56c6205465 --- /dev/null +++ b/include/download-instructions/windows-chocolatey.php @@ -0,0 +1,10 @@ +

+On the command line, run the following commands: +

+

+# Download and install Chocolatey.
+powershell -c "irm https://community.chocolatey.org/install.ps1|iex"
+
+# Download and install PHP.
+choco install php --version= -y
+
diff --git a/include/download-instructions/windows-native.php b/include/download-instructions/windows-native.php new file mode 100644 index 0000000000..23e0e118cc --- /dev/null +++ b/include/download-instructions/windows-native.php @@ -0,0 +1,7 @@ +

+On the command line, run the following commands: +

+

+# Download and install PHP.
+powershell -c "& ([ScriptBlock]::Create((irm 'https://www.php.net/include/download-instructions/windows.ps1'))) -Version "
+
diff --git a/include/download-instructions/windows-scoop.php b/include/download-instructions/windows-scoop.php new file mode 100644 index 0000000000..b95b7d1992 --- /dev/null +++ b/include/download-instructions/windows-scoop.php @@ -0,0 +1,11 @@ +

+On the command line, run the following commands: +

+

+# Download and install Scoop.
+powershell -c "irm https://get.scoop.sh | iex"
+
+# Download and install PHP.
+scoop bucket add versions
+scoop install php
+
diff --git a/include/download-instructions/windows-source.php b/include/download-instructions/windows-source.php new file mode 100644 index 0000000000..beacab7f70 --- /dev/null +++ b/include/download-instructions/windows-source.php @@ -0,0 +1,4 @@ +

+ The instructions for compiling from source + on Windows are described in the PHP manual. +

diff --git a/include/download-instructions/windows.ps1 b/include/download-instructions/windows.ps1 new file mode 100644 index 0000000000..d6ac1bad52 --- /dev/null +++ b/include/download-instructions/windows.ps1 @@ -0,0 +1,228 @@ +<# +.SYNOPSIS +Downloads and sets up a specified PHP version on Windows. + +.PARAMETER Version +Major.minor or full version (e.g., 7.4 or 7.4.30). + +.PARAMETER Path +Destination directory (defaults to C:\php). + +.PARAMETER Arch +Architecture: x64 or x86 (default: x64). + +.PARAMETER ThreadSafe +ThreadSafe: download Thread Safe build (default: $False). + +.PARAMETER Timezone +date.timezone string for php.ini (default: 'UTC'). +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory = $true, Position=0)] + [ValidatePattern('^\d+(\.\d+)?(\.\d+)?((alpha|beta|RC)\d*)?$')] + [string]$Version, + [Parameter(Mandatory = $false, Position=1)] + [string]$Path = "C:\php$Version", + [Parameter(Mandatory = $false, Position=2)] + [ValidateSet("x64", "x86")] + [string]$Arch = "x64", + [Parameter(Mandatory = $false, Position=3)] + [bool]$ThreadSafe = $False, + [Parameter(Mandatory = $false, Position=4)] + [string]$Timezone = 'UTC' +) + +Function Get-File { + param ( + [Parameter(Mandatory = $true, Position=0)] + [ValidateNotNullOrEmpty()] + [string] $Url, + [Parameter(Mandatory = $false, Position=1)] + [string] $FallbackUrl, + [Parameter(Mandatory = $false, Position=2)] + [string] $OutFile = '', + [Parameter(Mandatory = $false, Position=3)] + [int] $Retries = 3, + [Parameter(Mandatory = $false, Position=4)] + [int] $TimeoutSec = 0 + ) + + for ($i = 0; $i -lt $Retries; $i++) { + try { + if($OutFile -ne '') { + Invoke-WebRequest -Uri $Url -OutFile $OutFile -TimeoutSec $TimeoutSec + } else { + Invoke-WebRequest -Uri $Url -TimeoutSec $TimeoutSec + } + break; + } catch { + if ($i -eq ($Retries - 1)) { + if($FallbackUrl) { + try { + if($OutFile -ne '') { + Invoke-WebRequest -Uri $FallbackUrl -OutFile $OutFile -TimeoutSec $TimeoutSec + } else { + Invoke-WebRequest -Uri $FallbackUrl -TimeoutSec $TimeoutSec + } + } catch { + throw "Failed to download the file from $Url and $FallbackUrl" + } + } else { + throw "Failed to download the file from $Url" + } + } + } + } +} + +Function Get-Semver { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true, Position=0)] + [ValidateNotNull()] + [ValidatePattern('^\d+\.\d+$')] + [string]$Version + ) + $releases = Get-File -Url "https://downloads.php.net/~windows/releases/releases.json" | ConvertFrom-Json + $semver = $releases.$Version.version + if($null -eq $semver) { + $semver = (Get-File -Url "https://downloads.php.net/~windows/releases/archives").Links | + Where-Object { $_.href -match "php-($Version.[0-9]+).*" } | + ForEach-Object { $matches[1] } | + Sort-Object { [System.Version]$_ } -Descending | + Select-Object -First 1 + } + if($null -eq $semver) { + throw "Unsupported PHP version: $Version" + } + return $semver +} + +Function Get-VSVersion { + param( + [Parameter(Mandatory = $true, Position=0)] + [ValidateNotNull()] + [ValidatePattern('^\d+\.\d+$')] + [string]$Version + ) + $map = @{ + '5.2' = 'VC6' + '5.3' = 'VC9'; '5.4' = 'VC9' + '5.5' = 'VC11'; '5.6' = 'VC11' + '7.0' = 'VC14'; '7.1' = 'VC14' + '7.2' = 'VC15'; '7.3' = 'VC15'; '7.4' = 'vc15' + '8.0' = 'vs16'; '8.1' = 'vs16'; '8.2' = 'vs16'; '8.3' = 'vs16' + '8.4' = 'vs17'; '8.5' = 'vs17' + } + + if ($map.ContainsKey($Version)) { + return $map[$Version] + } + throw "Unsupported PHP version: $Version" +} + +Function Get-ReleaseType { + param( + [Parameter(Mandatory = $true, Position=0)] + [ValidateNotNull()] + [ValidatePattern('^\d+(\.\d+)?(\.\d+)?((alpha|beta|RC)\d*)?$')] + [string]$Version + ) + if ($Version -match "[a-zA-Z]") { + return "qa" + } else { + return "releases" + } +} + +Function Get-PhpFromUrl { + param( + [Parameter(Mandatory = $true, Position=0)] + [ValidateNotNull()] + [ValidatePattern('^\d+\.\d+$')] + [string]$Version, + [Parameter(Mandatory = $true, Position=1)] + [ValidateNotNull()] + [ValidatePattern('^\d+(\.\d+)?(\.\d+)?((alpha|beta|RC)\d*)?$')] + [string]$Semver, + [Parameter(Mandatory = $false, Position=2)] + [ValidateSet("x64", "x86")] + [string]$Arch = "x64", + [Parameter(Mandatory = $false, Position=3)] + [bool]$ThreadSafe = $false, + [Parameter(Mandatory = $true, Position=4)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string]$OutFile + ) + $vs = Get-VSVersion $Version + $ts = if ($ThreadSafe) { "ts" } else { "nts" } + $zipName = if ($ThreadSafe) { "php-$Semver-Win32-$vs-$Arch.zip" } else { "php-$Semver-$ts-Win32-$vs-$Arch.zip" } + $type = Get-ReleaseType $Version + + $base = "https://downloads.php.net/~windows/$type" + try { + Get-File -Url "$base/$zipName" -OutFile $OutFile + } catch { + try { + Get-File -Url "$base/archives/$zipName" -OutFile $OutFile + } catch { + throw "Failed to download PHP $Semver." + } + } +} + +$tempFile = [IO.Path]::ChangeExtension([IO.Path]::GetTempFileName(), '.zip') +try { + if ($Version -match "^\d+\.\d+$") { + $Semver = Get-Semver $Version + } else { + $Semver = $Version + $Semver -match '^(\d+\.\d+)' | Out-Null + $Version = $Matches[1] + } + + if (-not (Test-Path $Path)) { + try { + New-Item -ItemType Directory -Path $Path -ErrorAction Stop | Out-Null + } catch { + throw "Failed to create directory $Path. $_" + } + } else { + $files = Get-ChildItem -Path $Path + if ($files.Count -gt 0) { + throw "The directory $Path is not empty. Please provide an empty directory." + } + } + + if($Version -lt '5.5' -and $Arch -eq 'x64') { + $Arch = 'x86' + Write-Host "PHP version $Version does not support x64 architecture on Windows. Using x86 instead." + } + + Write-Host "Downloading PHP $Semver to $Path" + Get-PhpFromUrl $Version $Semver $Arch $ThreadSafe $tempFile + Expand-Archive -Path $tempFile -DestinationPath $Path -Force -ErrorAction Stop + + $phpIniProd = Join-Path $Path "php.ini-production" + if(-not(Test-Path $phpIniProd)) { + $phpIniProd = Join-Path $Path "php.ini-recommended" + } + $phpIni = Join-Path $Path "php.ini" + Copy-Item $phpIniProd $phpIni -Force + $extensionDir = Join-Path $Path "ext" + (Get-Content $phpIni) -replace '^extension_dir = "./"', "extension_dir = `"$extensionDir`"" | Set-Content $phpIni + (Get-Content $phpIni) -replace ';\s?extension_dir = "ext"', "extension_dir = `"$extensionDir`"" | Set-Content $phpIni + (Get-Content $phpIni) -replace ';\s?date.timezone =', "date.timezone = `"$Timezone`"" | Set-Content $phpIni + + Write-Host "PHP $Semver downloaded to $Path" +} catch { + Write-Error $_ + Exit 1 +} finally { + if (Test-Path $tempFile) { + Remove-Item $tempFile -Force -ErrorAction SilentlyContinue + } +} diff --git a/include/header.inc b/include/header.inc index c31b73ebad..3da277344c 100644 --- a/include/header.inc +++ b/include/header.inc @@ -23,6 +23,14 @@ foreach($css_files as $filename) { $CSS[$filename] = @filemtime($path); } +$JS = []; +if (isset($config["js_files"])) { + foreach($config['js_files'] as $filename) { + $path = dirname(__DIR__) . '/' . $filename; + $JS[$filename] = @filemtime($path); + } +} + if (isset($shortname) && $shortname) { header("Link: <$shorturl>; rel=shorturl"); } @@ -89,6 +97,18 @@ if (!isset($config["languages"])) { " hreflang=""> + $modified): ?> + + + + $modified): ?> + + + + + "> + + diff --git a/include/version.inc b/include/version.inc index 82a5084dc3..d5a400626e 100644 --- a/include/version.inc +++ b/include/version.inc @@ -107,3 +107,55 @@ function release_get_latest() { return [$version, $current]; } + +function show_source_releases() +{ + global $RELEASES; + + $SHOW_COUNT = 4; + + $i = 0; foreach ($RELEASES as $MAJOR => $major_releases): /* major releases loop start */ + $releases = array_slice($major_releases, 0, $SHOW_COUNT); +?> + + $a): ?> + + + +

+ + PHP + (Changelog) +

+
+ + + + GPG Keys for PHP +
+ + +=g.reach);A+=w.value.length,w=w.next){var P=w.value;if(n.length>e.length)return;if(!(P instanceof i)){var E,S=1;if(y){if(!(E=l(b,A,e,m))||E.index>=e.length)break;var L=E.index,O=E.index+E[0].length,C=A;for(C+=w.value.length;L>=C;)C+=(w=w.next).value.length;if(A=C-=w.value.length,w.value instanceof i)continue;for(var j=w;j!==n.tail&&(Cg.reach&&(g.reach=W);var I=w.prev;if(_&&(I=u(n,I,_),A+=_.length),c(n,I,S),w=u(n,I,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),S>1){var T={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,T),g&&T.reach>g.reach&&(g.reach=T.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a"+i.content+""},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); +!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",a={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},n={bash:a,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},parameter:{pattern:/(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:n},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:a}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:n},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:n.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:n.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},a.inside=e.languages.bash;for(var s=["comment","function-name","for-or-select","assign-left","parameter","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=n.variable[1].inside,i=0;i/,lookbehind:!0},{pattern:/(^|[^`])#.*/,lookbehind:!0}],string:[{pattern:/"(?:`[\s\S]|[^`"])*"/,greedy:!0,inside:null},{pattern:/'(?:[^']|'')*'/,greedy:!0}],namespace:/\[[a-z](?:\[(?:\[[^\]]*\]|[^\[\]])*\]|[^\[\]])*\]/i,boolean:/\$(?:false|true)\b/i,variable:/\$\w+\b/,function:[/\b(?:Add|Approve|Assert|Backup|Block|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|ForEach|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Sort|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Tee|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Where|Write)-[a-z]+\b/i,/\b(?:ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i],keyword:/\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i,operator:{pattern:/(^|\W)(?:!|-(?:b?(?:and|x?or)|as|(?:Not)?(?:Contains|In|Like|Match)|eq|ge|gt|is(?:Not)?|Join|le|lt|ne|not|Replace|sh[lr])\b|-[-=]?|\+[+=]?|[*\/%]=?)/i,lookbehind:!0},punctuation:/[|{}[\];(),.]/};i.string[0].inside={function:{pattern:/(^|[^`])\$\((?:\$\([^\r\n()]*\)|(?!\$\()[^\r\n)])*\)/,lookbehind:!0,inside:i},boolean:i.boolean,variable:i.variable}}(Prism); +!function(){if("undefined"!=typeof Prism&&"undefined"!=typeof document){var e="line-numbers",n=/\n(?!$)/g,t=Prism.plugins.lineNumbers={getLine:function(n,t){if("PRE"===n.tagName&&n.classList.contains(e)){var i=n.querySelector(".line-numbers-rows");if(i){var r=parseInt(n.getAttribute("data-start"),10)||1,s=r+(i.children.length-1);ts&&(t=s);var l=t-r;return i.children[l]}}},resize:function(e){r([e])},assumeViewportIndependence:!0},i=void 0;window.addEventListener("resize",(function(){t.assumeViewportIndependence&&i===window.innerWidth||(i=window.innerWidth,r(Array.prototype.slice.call(document.querySelectorAll("pre.line-numbers"))))})),Prism.hooks.add("complete",(function(t){if(t.code){var i=t.element,s=i.parentNode;if(s&&/pre/i.test(s.nodeName)&&!i.querySelector(".line-numbers-rows")&&Prism.util.isActive(i,e)){i.classList.remove(e),s.classList.add(e);var l,o=t.code.match(n),a=o?o.length+1:1,u=new Array(a+1).join("");(l=document.createElement("span")).setAttribute("aria-hidden","true"),l.className="line-numbers-rows",l.innerHTML=u,s.hasAttribute("data-start")&&(s.style.counterReset="linenumber "+(parseInt(s.getAttribute("data-start"),10)-1)),t.element.appendChild(l),r([s]),Prism.hooks.run("line-numbers",t)}}})),Prism.hooks.add("line-numbers",(function(e){e.plugins=e.plugins||{},e.plugins.lineNumbers=!0}))}function r(e){if(0!=(e=e.filter((function(e){var n,t=(n=e,n?window.getComputedStyle?getComputedStyle(n):n.currentStyle||null:null)["white-space"];return"pre-wrap"===t||"pre-line"===t}))).length){var t=e.map((function(e){var t=e.querySelector("code"),i=e.querySelector(".line-numbers-rows");if(t&&i){var r=e.querySelector(".line-numbers-sizer"),s=t.textContent.split(n);r||((r=document.createElement("span")).className="line-numbers-sizer",t.appendChild(r)),r.innerHTML="0",r.style.display="block";var l=r.getBoundingClientRect().height;return r.innerHTML="",{element:e,lines:s,lineHeights:[],oneLinerHeight:l,sizer:r}}})).filter(Boolean);t.forEach((function(e){var n=e.sizer,t=e.lines,i=e.lineHeights,r=e.oneLinerHeight;i[t.length-1]=void 0,t.forEach((function(e,t){if(e&&e.length>1){var s=n.appendChild(document.createElement("span"));s.style.display="block",s.textContent=e}else i[t]=r}))})),t.forEach((function(e){for(var n=e.sizer,t=e.lineHeights,i=0,r=0;r