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