Windows 10 + IIS + PHP FastCGI + 全部放 D 盘 来安装。PHP 跑 IIS 要用 Non Thread Safe / NTS 版本,这是 PHP 官方对 IIS FastCGI 的推荐;IIS 需要启用 CGI/FastCGI 组件
一、准备目录
以管理员身份打开 PowerShell,先创建目录:
mkdir D:\php
mkdir D:\wwwroot
mkdir D:\wwwroot\default
网站目录建议:D:\wwwroot\default
PHP 安装目录:D:\php
二、安装 IIS
以管理员身份打开 PowerShell
Enable-WindowsOptionalFeature -Online -FeatureName IIS-WebServerRole -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-CGI -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-ManagementConsole -All
二、安装PHP
下面这段直接 复制到“管理员 PowerShell”里执行,会自动完成:
- 启用 IIS + CGI/FastCGI
- 安装 VC++ 运行库
- 自动下载 PHP 官方 Windows 版 x64 NTS
- 解压到 D:\php
- 网站目录设置为 D:\wwwroot\default
- 配置 IIS 识别 .php
- 创建 phpinfo() 测试页
- 放行 80 端口
管理员 PowerShell 执行
$ErrorActionPreference = "Stop"
# ========= 基础路径 =========
$PhpDir = "D:\php"
$WebRoot = "D:\wwwroot"
$SiteDir = "D:\wwwroot\default"
$TempDir = "$env:TEMP\iis_php_install"
# ========= 检查管理员权限 =========
$IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
if (-not $IsAdmin) {
throw "请右键 PowerShell,选择【以管理员身份运行】后再执行。"
}
# ========= 检查 D 盘 =========
if (-not (Test-Path "D:\")) {
throw "未检测到 D 盘,请确认服务器有 D 盘。"
}
# ========= 创建目录 =========
New-Item -ItemType Directory -Force -Path $PhpDir, $WebRoot, $SiteDir, $TempDir | Out-Null
# ========= 启用 TLS 1.2 =========
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Write-Host "正在启用 IIS / CGI / FastCGI..." -ForegroundColor Cyan
Enable-WindowsOptionalFeature -Online -FeatureName IIS-WebServerRole -All -NoRestart | Out-Null
Enable-WindowsOptionalFeature -Online -FeatureName IIS-WebServer -All -NoRestart | Out-Null
Enable-WindowsOptionalFeature -Online -FeatureName IIS-CommonHttpFeatures -All -NoRestart | Out-Null
Enable-WindowsOptionalFeature -Online -FeatureName IIS-DefaultDocument -All -NoRestart | Out-Null
Enable-WindowsOptionalFeature -Online -FeatureName IIS-StaticContent -All -NoRestart | Out-Null
Enable-WindowsOptionalFeature -Online -FeatureName IIS-HttpErrors -All -NoRestart | Out-Null
Enable-WindowsOptionalFeature -Online -FeatureName IIS-RequestFiltering -All -NoRestart | Out-Null
Enable-WindowsOptionalFeature -Online -FeatureName IIS-CGI -All -NoRestart | Out-Null
Enable-WindowsOptionalFeature -Online -FeatureName IIS-ManagementConsole -All -NoRestart | Out-Null
# ========= 安装 VC++ 运行库 =========
Write-Host "正在下载并安装 VC++ x64 运行库..." -ForegroundColor Cyan
$VcUrl = "https://aka.ms/vc14/vc_redist.x64.exe"
$VcExe = Join-Path $TempDir "vc_redist.x64.exe"
Invoke-WebRequest -Uri $VcUrl -OutFile $VcExe -UseBasicParsing
Start-Process -FilePath $VcExe -ArgumentList "/install /quiet /norestart" -Wait
# ========= 自动获取 PHP 最新 NTS x64 ZIP =========
Write-Host "正在获取 PHP 官方 Windows NTS x64 下载地址..." -ForegroundColor Cyan
$DownloadPage = Invoke-WebRequest -Uri "https://windows.php.net/download/" -UseBasicParsing
$Html = $DownloadPage.Content
$Matches = [regex]::Matches($Html, 'href="([^"]*php-(\d+\.\d+\.\d+)-nts-Win32-vs(?:16|17)-x64\.zip)"')
if ($Matches.Count -eq 0) {
throw "没有找到 PHP NTS x64 下载链接,请手动检查 https://windows.php.net/download/"
}
$PhpItems = foreach ($m in $Matches) {
$href = $m.Groups[1].Value
$ver = [version]$m.Groups[2].Value
if ($href -like "http*") {
$url = $href
} elseif ($href.StartsWith("/")) {
$url = "https://windows.php.net$href"
} else {
$url = "https://windows.php.net/download/$href"
}
[PSCustomObject]@{
Version = $ver
Url = $url
}
}
$LatestPhp = $PhpItems | Sort-Object Version -Descending | Select-Object -First 1
$PhpZip = Join-Path $TempDir "php.zip"
Write-Host "即将下载 PHP $($LatestPhp.Version):" -ForegroundColor Green
Write-Host $LatestPhp.Url
Invoke-WebRequest -Uri $LatestPhp.Url -OutFile $PhpZip -UseBasicParsing
# ========= 备份旧 PHP 目录 =========
if (Test-Path "$PhpDir\php.exe") {
$BackupDir = "D:\php_backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
Write-Host "检测到旧 PHP,备份到:$BackupDir" -ForegroundColor Yellow
Rename-Item -Path $PhpDir -NewName $BackupDir
New-Item -ItemType Directory -Force -Path $PhpDir | Out-Null
}
# ========= 解压 PHP =========
Write-Host "正在解压 PHP 到 $PhpDir..." -ForegroundColor Cyan
Expand-Archive -Path $PhpZip -DestinationPath $PhpDir -Force
# ========= 配置 php.ini =========
Write-Host "正在配置 php.ini..." -ForegroundColor Cyan
Copy-Item "$PhpDir\php.ini-production" "$PhpDir\php.ini" -Force
$TmpPhp = "$PhpDir\tmp"
New-Item -ItemType Directory -Force -Path $TmpPhp | Out-Null
Add-Content "$PhpDir\php.ini" @"
; ===== Auto IIS PHP Config =====
extension_dir = "$PhpDir\ext"
cgi.force_redirect = 0
cgi.fix_pathinfo = 1
fastcgi.impersonate = 1
date.timezone = Asia/Shanghai
upload_tmp_dir = "$TmpPhp"
session.save_path = "$TmpPhp"
extension=curl
extension=fileinfo
extension=gd
extension=mbstring
extension=mysqli
extension=openssl
extension=pdo_mysql
extension=zip
"@
# ========= 添加 PHP 到系统 PATH =========
Write-Host "正在添加 PHP 到系统环境变量 PATH..." -ForegroundColor Cyan
$MachinePath = [Environment]::GetEnvironmentVariable("Path", "Machine")
if ($MachinePath -notlike "*$PhpDir*") {
[Environment]::SetEnvironmentVariable("Path", "$MachinePath;$PhpDir", "Machine")
}
# ========= 配置 IIS =========
Write-Host "正在配置 IIS FastCGI / PHP 处理程序..." -ForegroundColor Cyan
$AppCmd = "$env:windir\System32\inetsrv\appcmd.exe"
$PhpCgi = "$PhpDir\php-cgi.exe"
if (-not (Test-Path $PhpCgi)) {
throw "未找到 $PhpCgi,PHP 解压可能失败。"
}
# 注册 FastCGI,重复时忽略错误
& $AppCmd set config -section:system.webServer/fastCgi /+"[fullPath='$PhpCgi']" /commit:apphost 2>$null
# 删除旧 PHP handler,避免重复
& $AppCmd set config -section:system.webServer/handlers /-"[name='PHP_via_FastCGI']" /commit:apphost 2>$null
# 添加 PHP handler
& $AppCmd set config -section:system.webServer/handlers /+"[name='PHP_via_FastCGI',path='*.php',verb='*',modules='FastCgiModule',scriptProcessor='$PhpCgi',resourceType='Either',requireAccess='Script']" /commit:apphost
# 设置默认站点目录到 D 盘
Import-Module WebAdministration
Set-ItemProperty "IIS:\Sites\Default Web Site" -Name physicalPath -Value $SiteDir
# 添加 index.php 默认文档,重复时忽略
& $AppCmd set config "Default Web Site" -section:system.webServer/defaultDocument /+"files.[value='index.php']" /commit:apphost 2>$null
# ========= 创建测试页 =========
@"
<?php
phpinfo();
"@ | Set-Content -Path "$SiteDir\index.php" -Encoding UTF8
# ========= 权限 =========
Write-Host "正在设置 IIS 访问权限..." -ForegroundColor Cyan
icacls $WebRoot /grant "IIS_IUSRS:(OI)(CI)(RX)" /T | Out-Null
icacls $PhpDir /grant "IIS_IUSRS:(OI)(CI)(RX)" /T | Out-Null
icacls $TmpPhp /grant "IIS_IUSRS:(OI)(CI)(M)" /T | Out-Null
# ========= 防火墙放行 80 =========
if (-not (Get-NetFirewallRule -DisplayName "IIS HTTP 80" -ErrorAction SilentlyContinue)) {
New-NetFirewallRule -DisplayName "IIS HTTP 80" -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow | Out-Null
}
# ========= 重启 IIS =========
Write-Host "正在重启 IIS..." -ForegroundColor Cyan
iisreset | Out-Null
# ========= 输出结果 =========
Write-Host ""
Write-Host "==================================================" -ForegroundColor Green
Write-Host "安装完成!" -ForegroundColor Green
Write-Host "PHP 目录:$PhpDir" -ForegroundColor Green
Write-Host "网站目录:$SiteDir" -ForegroundColor Green
Write-Host "测试地址:http://localhost/" -ForegroundColor Green
Write-Host "外网访问:http://服务器IP/" -ForegroundColor Green
Write-Host "==================================================" -ForegroundColor Green
& "$PhpDir\php.exe" -v
执行完成后,浏览器打开:http://localhost/
或者外部访问:http://你的服务器IP/
看到 phpinfo() 页面就说明成功。
----------
三、安装 IIS URL Rewrite 模块
管理员 PowerShell 执行:
$ErrorActionPreference = "Stop"
$TempDir = "$env:TEMP\iis_url_rewrite"
New-Item -ItemType Directory -Force -Path $TempDir | Out-Null
$RewriteMsi = Join-Path $TempDir "rewrite_amd64_zh-CN.msi"
$RewriteUrl = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_zh-CN.msi"
Write-Host "正在下载 IIS URL Rewrite 模块..." -ForegroundColor Cyan
Invoke-WebRequest -Uri $RewriteUrl -OutFile $RewriteMsi -UseBasicParsing
Write-Host "正在安装 IIS URL Rewrite 模块..." -ForegroundColor Cyan
Start-Process msiexec.exe -ArgumentList "/i `"$RewriteMsi`" /qn /norestart" -Wait
Write-Host "正在重启 IIS..." -ForegroundColor Cyan
iisreset
Write-Host "URL Rewrite 安装完成。" -ForegroundColor Green
安装完成后,打开 IIS 管理器,站点里应该能看到:
URL Rewrite / URL 重写
常用检查命令
重启 IIS:
iisreset
查看 IIS 服务:
Get-Service W3SVC
检查 80 端口:
netstat -ano | findstr :80
检查 PHP:
D:\php\php.exe -v
D:\php\php-cgi.exe -v
如果PHP错误,使用这份
# ================================
# Windows 10 / Windows Server
# IIS + PHP 8.2 自动安装配置脚本
# 安装目录:D:\php
# 自动识别 IIS 实际网站目录
# ================================
$ErrorActionPreference = "Stop"
# ===== 基础配置 =====
$PhpDir = "D:\php"
$PhpZip = "D:\php.zip"
$PhpUrl = "https://windows.php.net/downloads/releases/php-8.2.32-Win32-vs16-x64.zip"
$TimeZone = "Asia/Shanghai"
$HandlerName = "PHP_via_FastCGI"
Write-Host "==================================================" -ForegroundColor Green
Write-Host "开始安装 IIS + PHP" -ForegroundColor Green
Write-Host "PHP 安装目录:$PhpDir" -ForegroundColor Green
Write-Host "==================================================" -ForegroundColor Green
# ===== 检查管理员权限 =====
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Host "请使用【管理员身份】运行 PowerShell!" -ForegroundColor Red
exit 1
}
# ===== 启用 TLS 1.2,避免下载失败 =====
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# ===== 安装 IIS 必要组件 =====
Write-Host "正在启用 IIS 组件..." -ForegroundColor Yellow
$features = @(
"IIS-WebServerRole",
"IIS-WebServer",
"IIS-CommonHttpFeatures",
"IIS-DefaultDocument",
"IIS-DirectoryBrowsing",
"IIS-HttpErrors",
"IIS-StaticContent",
"IIS-CGI",
"IIS-RequestFiltering",
"IIS-ManagementConsole"
)
foreach ($feature in $features) {
Enable-WindowsOptionalFeature -Online -FeatureName $feature -All -NoRestart | Out-Null
}
# ===== 清理旧 PHP 文件 =====
Write-Host "正在清理旧 PHP 目录..." -ForegroundColor Yellow
if (Test-Path $PhpDir) {
$backupDir = "D:\php_backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
Rename-Item $PhpDir $backupDir -Force
Write-Host "旧 PHP 目录已备份到:$backupDir" -ForegroundColor Yellow
}
if (Test-Path $PhpZip) {
Remove-Item $PhpZip -Force
}
# ===== 下载 PHP =====
Write-Host "正在下载 PHP..." -ForegroundColor Yellow
Write-Host $PhpUrl -ForegroundColor Gray
Invoke-WebRequest -Uri $PhpUrl -OutFile $PhpZip
if (-not (Test-Path $PhpZip)) {
Write-Host "PHP 下载失败,未找到 D:\php.zip" -ForegroundColor Red
exit 1
}
# ===== 解压 PHP =====
Write-Host "正在解压 PHP 到 $PhpDir ..." -ForegroundColor Yellow
New-Item -ItemType Directory -Path $PhpDir -Force | Out-Null
Expand-Archive $PhpZip -DestinationPath $PhpDir -Force
if (-not (Test-Path "$PhpDir\php.exe")) {
Write-Host "PHP 解压失败:未找到 $PhpDir\php.exe" -ForegroundColor Red
exit 1
}
if (-not (Test-Path "$PhpDir\php-cgi.exe")) {
Write-Host "PHP 解压失败:未找到 $PhpDir\php-cgi.exe" -ForegroundColor Red
exit 1
}
# ===== 创建 tmp 目录 =====
New-Item -ItemType Directory -Path "$PhpDir\tmp" -Force | Out-Null
# ===== 生成 php.ini =====
Write-Host "正在生成 php.ini..." -ForegroundColor Yellow
if (Test-Path "$PhpDir\php.ini-production") {
Copy-Item "$PhpDir\php.ini-production" "$PhpDir\php.ini" -Force
} elseif (Test-Path "$PhpDir\php.ini-development") {
Copy-Item "$PhpDir\php.ini-development" "$PhpDir\php.ini" -Force
} else {
New-Item -ItemType File -Path "$PhpDir\php.ini" -Force | Out-Null
}
# ===== 写入常用 PHP 配置 =====
@"
; ===== Custom PHP Settings =====
extension_dir="$PhpDir\ext"
cgi.force_redirect=0
cgi.fix_pathinfo=1
fastcgi.impersonate=1
date.timezone="$TimeZone"
upload_tmp_dir="$PhpDir\tmp"
session.save_path="$PhpDir\tmp"
memory_limit=256M
post_max_size=64M
upload_max_filesize=64M
max_execution_time=300
max_input_time=300
extension=mbstring
extension=mysqli
extension=pdo_mysql
extension=curl
extension=gd
extension=openssl
extension=fileinfo
extension=exif
extension=zip
"@ | Add-Content "$PhpDir\php.ini" -Encoding UTF8
# ===== 添加 PHP 到系统 PATH =====
Write-Host "正在添加 PHP 到系统环境变量 PATH..." -ForegroundColor Yellow
$machinePath = [Environment]::GetEnvironmentVariable("Path", "Machine")
if ($machinePath -notlike "*$PhpDir*") {
[Environment]::SetEnvironmentVariable("Path", "$machinePath;$PhpDir", "Machine")
}
# 当前窗口也临时生效
$env:Path = "$env:Path;$PhpDir"
# ===== 设置权限 =====
Write-Host "正在设置 PHP tmp 目录权限..." -ForegroundColor Yellow
icacls "$PhpDir\tmp" /grant "IIS_IUSRS:(OI)(CI)(M)" /T | Out-Null
icacls "$PhpDir\tmp" /grant "IUSR:(OI)(CI)(M)" /T | Out-Null
# ===== 测试 PHP CLI =====
Write-Host "正在测试 PHP..." -ForegroundColor Yellow
& "$PhpDir\php.exe" -v
# ===== 配置 IIS FastCGI =====
Write-Host "正在配置 IIS FastCGI..." -ForegroundColor Yellow
$appcmd = "$env:SystemRoot\System32\inetsrv\appcmd.exe"
$phpCgi = "$PhpDir\php-cgi.exe"
if (-not (Test-Path $appcmd)) {
Write-Host "未找到 appcmd.exe,请确认 IIS 是否安装成功。" -ForegroundColor Red
exit 1
}
# 删除旧 FastCGI 配置,避免重复报错
& $appcmd set config -section:system.webServer/fastCgi /-"[fullPath='$phpCgi']" 2>$null | Out-Null
# 删除旧 PHP Handler,避免重复报错
& $appcmd set config -section:system.webServer/handlers /-"[name='$HandlerName']" 2>$null | Out-Null
# 添加 FastCGI
& $appcmd set config -section:system.webServer/fastCgi /+"[fullPath='$phpCgi']"
# 添加 PHP Handler
& $appcmd set config -section:system.webServer/handlers /+"[name='$HandlerName',path='*.php',verb='*',modules='FastCgiModule',scriptProcessor='$phpCgi',resourceType='Either',requireAccess='Script']"
# ===== 获取 IIS 实际网站目录 =====
Write-Host "正在识别 IIS 网站根目录..." -ForegroundColor Yellow
Import-Module WebAdministration
$site = Get-Website | Where-Object { $_.Name -eq "Default Web Site" } | Select-Object -First 1
if (-not $site) {
$site = Get-Website | Select-Object -First 1
}
if (-not $site) {
Write-Host "没有找到 IIS 网站,请先创建网站。" -ForegroundColor Red
exit 1
}
$SiteName = $site.Name
$WebRoot = [Environment]::ExpandEnvironmentVariables($site.physicalPath)
Write-Host "检测到 IIS 网站:$SiteName" -ForegroundColor Green
Write-Host "检测到网站目录:$WebRoot" -ForegroundColor Green
New-Item -ItemType Directory -Path $WebRoot -Force | Out-Null
# 设置网站目录读取权限
icacls "$WebRoot" /grant "IIS_IUSRS:(OI)(CI)(RX)" /T | Out-Null
icacls "$WebRoot" /grant "IUSR:(OI)(CI)(RX)" /T | Out-Null
# ===== 添加 index.php 为默认文档 =====
Write-Host "正在设置 index.php 默认文档..." -ForegroundColor Yellow
& $appcmd set config "$SiteName" -section:system.webServer/defaultDocument /-"files.[value='index.php']" 2>$null | Out-Null
& $appcmd set config "$SiteName" -section:system.webServer/defaultDocument /+"files.[value='index.php']" 2>$null | Out-Null
# ===== 创建测试文件到正确网站目录 =====
Write-Host "正在创建 PHP 测试文件..." -ForegroundColor Yellow
Set-Content -Path "$WebRoot\info.php" -Value "<?php phpinfo();" -Encoding ASCII
Set-Content -Path "$WebRoot\index.php" -Value "<?php echo 'IIS + PHP is OK';" -Encoding ASCII
# ===== 重启 IIS =====
Write-Host "正在重启 IIS..." -ForegroundColor Yellow
iisreset
# ===== 输出检查信息 =====
Write-Host ""
Write-Host "==================================================" -ForegroundColor Green
Write-Host "安装完成!" -ForegroundColor Green
Write-Host "==================================================" -ForegroundColor Green
Write-Host "PHP 目录:" -ForegroundColor Cyan
Write-Host $PhpDir
Write-Host ""
Write-Host "IIS 网站名称:" -ForegroundColor Cyan
Write-Host $SiteName
Write-Host ""
Write-Host "IIS 网站目录:" -ForegroundColor Cyan
Write-Host $WebRoot
Write-Host ""
Write-Host "PHP 测试地址:" -ForegroundColor Green
Write-Host "http://localhost/info.php"
Write-Host ""
Write-Host "网站首页测试:" -ForegroundColor Green
Write-Host "http://localhost/"
Write-Host ""
Write-Host "外网访问:" -ForegroundColor Green
Write-Host "http://服务器IP/"
Write-Host ""
Write-Host "PHP Handler 检查:" -ForegroundColor Cyan
& $appcmd list config -section:system.webServer/handlers | findstr PHP
Write-Host ""
Write-Host "PHP 版本检查:" -ForegroundColor Cyan
& "$PhpDir\php.exe" -v
Write-Host "==================================================" -ForegroundColor Green
运行前如果 PowerShell 不允许执行脚本,先执行一次:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
然后运行:
D:\install_iis_php.ps1