wp-php-toolkit/corsproxy 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

wp-php-toolkit/corsproxy

最新稳定版本:v0.7.4

Composer 安装命令:

composer require wp-php-toolkit/corsproxy

包简介

CORSProxy component for WordPress.

README 文档

README

slug corsproxy
title CORSProxy
install wp-php-toolkit/corsproxy
see_also
httpclient | HttpClient | Fetch upstream responses from PHP when browser CORS blocks direct access. httpserver | HttpServer | Understand the local-server shape before deploying a proxy endpoint.

A small PHP CORS proxy intended for browser-side code that needs to reach servers without CORS headers.

Why this exists

A Playground-style browser tool reads https://api.github.com/repos/WordPress/php-toolkit, a plugin ZIP from downloads.wordpress.org, or a raw fixture from GitHub. The browser blocks the response when the upstream server does not send the required CORS headers, even though PHP can fetch the same public URL server-side.

The CORSProxy component is that server-side bridge. It accepts a target URL, fetches it from PHP, and returns a browser-readable response. Because an open proxy is a security and abuse risk, real deployments should add host allowlists, rate limits, header controls, and private-network protections appropriate to their environment.

Run the proxy locally

Run on your machine: the proxy needs to listen on a port. Start PHP's built-in server and request any HTTPS URL through it.

PLAYGROUND_CORS_PROXY_DISABLE_RATE_LIMIT=1 \
  php -S 127.0.0.1:5263 vendor/wp-php-toolkit/corsproxy/cors-proxy.php

# In another terminal:
curl -s "http://127.0.0.1:5263/cors-proxy.php/https://api.github.com/repos/WordPress/php-toolkit" | head

Production rate limiting

Drop a cors-proxy-config.php next to cors-proxy.php. If that file defines a playground_cors_proxy_maybe_rate_limit() function, the proxy calls it before forwarding any request — your one chance to reject early. Without the file, the proxy applies its default rate limiter, which is fine for development but should be replaced for any deployment that gets real traffic.

This example uses a per-IP token bucket stored on disk. Replace with Redis or memcached for multi-host deployments.

<?php
// cors-proxy-config.php — placed next to cors-proxy.php.

function playground_cors_proxy_maybe_rate_limit() {
	$ip      = isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
	$bucket  = sys_get_temp_dir() . '/cors-rl-' . md5( $ip );
	$now     = time();
	$window  = 60;
	$max_req = 30;

	$hits = array();
	if ( file_exists( $bucket ) ) {
		$hits = json_decode( file_get_contents( $bucket ), true );
		if ( ! is_array( $hits ) ) $hits = array();
	}
	$hits = array_filter( $hits, function ( $t ) use ( $now, $window ) {
		return $t > $now - $window;
	} );

	if ( count( $hits ) >= $max_req ) {
		header( 'Retry-After: ' . $window );
		http_response_code( 429 );
		echo 'Rate limit exceeded';
		exit;
	}

	$hits[] = $now;
	file_put_contents( $bucket, json_encode( array_values( $hits ) ) );
}

echo "Config loaded — rate limiter armed.\n";

Allowlist upstream hosts

Out of the box the proxy will fetch any public URL. Most real deployments want a fixed list of upstreams — GitHub, Packagist, wp.org. Both the rate-limit logic and the allowlist live in the same hook, since cors-proxy.php only calls playground_cors_proxy_maybe_rate_limit() once. The example below shows just the allowlist concern; in practice you stack both in one function inside cors-proxy-config.php.

<?php
// cors-proxy-config.php — combine with the rate-limit example above.

function playground_cors_proxy_maybe_rate_limit() {
	$allow = array(
		'api.github.com',
		'raw.githubusercontent.com',
		'codeload.github.com',
		'repo.packagist.org',
		'downloads.wordpress.org',
		'api.wordpress.org',
	);

	$target = isset( $_SERVER['PATH_INFO'] ) ? $_SERVER['PATH_INFO'] : ( '/' . ( isset( $_SERVER['QUERY_STRING'] ) ? $_SERVER['QUERY_STRING'] : '' ) );
	$target = ltrim( $target, '/' );
	$host   = parse_url( $target, PHP_URL_HOST );

	if ( ! $host || ! in_array( strtolower( $host ), $allow, true ) ) {
		http_response_code( 403 );
		header( 'Content-Type: text/plain' );
		echo "Upstream not allowed: " . ( $host ? $host : '(none)' );
		exit;
	}
}

echo "Allowlist config active.\n";

Browser-side fetch through the proxy

Once deployed, the client side is just fetch() with the proxy URL. Drop this into any HTML page.

const PROXY = "https://cors.example.com/cors-proxy.php";

async function viaProxy(url, init = {}) {
  const res = await fetch(`${PROXY}/${url}`, {
    ...init,
    headers: {
      ...(init.headers || {}),
      "X-Cors-Proxy-Allowed-Request-Headers": "Authorization",
    },
  });
  if (!res.ok) throw new Error(`Proxy returned ${res.status}`);
  return res;
}

const repo = await viaProxy("https://api.github.com/repos/WordPress/php-toolkit").then(r => r.json());
console.log(repo.full_name, repo.stargazers_count);

Deploy behind nginx

The proxy is a single PHP script — any SAPI works. nginx + php-fpm is a common production setup. PATH_INFO is what the proxy reads to learn the target URL.

server {
  listen 443 ssl http2;
  server_name cors.example.com;

  root /var/www/cors-proxy;
  index cors-proxy.php;

  location ~ ^/cors-proxy\.php(/.*)?$ {
    fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    fastcgi_split_path_info ^(.+\.php)(/.*)$;
    fastcgi_param SCRIPT_FILENAME $document_root/cors-proxy.php;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    include fastcgi_params;
  }
}

统计信息

  • 总下载量: 19
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 1
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: GPL-2.0-or-later
  • 更新时间: 2025-09-06

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固