How to Send CORS Headers in PHP

Introduction

In the realm of web development, one challenge that consistently emerges is ensuring seamless interaction between different origins or domains. This is where CORS, or Cross-Origin Resource Sharing, steps into the spotlight. As web developers, we often find ourselves in situations where our applications need to request resources from a domain other than the one that served the initial web page. This could be anything from loading CSS stylesheets, fetching JavaScript files, to making API calls to external services. However, due to security reasons, browsers restrict cross-origin HTTP requests initiated from scripts. Enter CORS—a mechanism that allows web servers to declare not just who can access their assets, but also how the resources can be utilized by external web pages.

Understanding and implementing CORS is pivotal for modern web applications, and PHP, being one of the most widely used server-side languages, offers a straightforward approach to handle CORS headers. Through this article, we aim to unravel how you can send CORS headers with PHP, thereby enhancing your application’s interoperability without compromising security.

Implementing CORS in a PHP application involves sending specific HTTP headers that instruct the browser on how to handle cross-origin requests. A simple way to do this is by adding header statements in your PHP scripts that serve the resources needing cross-origin access. These headers include Access-Control-Allow-Origin, which specifies which domains are allowed to access the resource, among others for controlling methods, headers, and credentials involved in the requests. The article will further delve into the technicalities and provide code examples to guide you through the implementation process.

CORS Headers Explained

At its core, CORS is a W3C standard that allows a server to relax the same-origin policy. This policy is a security measure that prevents malicious websites from accessing resources and data from another site without permission. While this policy is crucial for web security, it can be overly restrictive for legitimate cross-origin requests essential for modern web applications.

CORS operates by adding new HTTP headers that tell the browser to permit web applications running at one origin (domain) to access selected resources from a different origin. For example, if you have an application running on https://www.example-app.com that needs to access resources from https://api.example-service.com, CORS policies can be implemented to securely allow this interaction.

Sending CORS Headers in PHP the lazy way

The code below allows the services to be accessed by anyone any from any originating web address(es). This is usually not a good idea.

ref: https://stackoverflow.com/questions/8719276/cross-origin-request-headerscors-with-php-headers

/**
 *  An example CORS-compliant method.  It will allow any GET, POST, or OPTIONS requests from any
 *  origin.
 *
 *  In a production environment, you probably want to be more restrictive, but this gives you
 *  the general idea of what is involved.  For the nitty-gritty low-down, read:
 *
 *  - https://developer.mozilla.org/en/HTTP_access_control
 *  - https://fetch.spec.whatwg.org/#http-cors-protocol
 *
 */
function sendCORSHeaders() {
    
    // Allow from any origin
    if (isset($_SERVER['HTTP_ORIGIN'])) {
        // Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
        // you want to allow, and if so:
        header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
        header('Access-Control-Allow-Credentials: true');
        header('Access-Control-Max-Age: 86400');    // cache for 1 day
    }
    
    // Access-Control headers are received during OPTIONS requests
    if (!empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
        
        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
            // may also be using PUT, PATCH, HEAD etc
            header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
        
        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
            header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
    
        exit(0);
    }   
}

Sending CORS Headers in PHP (improved)

If your want to be better it’s highly recommended to do some checks.

Here’s an example that checks the origin (HTTP_ORIGIN header) and if it’s within the allowed domains list then it outputs the correct headers.

<?php

define('WPSANDBOX_TUTORIAL_909_ALLOWED_DOMAINS', [
	'localhost',
	'example.com',
]);


// send the headers
WPSandbox_Tutorial_909::sendCORSHeaders();

/**
 * This tutorial shows you how to send CORS headers in PHP
 * @see https://wpsandbox.net/909
 */
class WPSandbox_Tutorial_909 {
	/**
	 * WPSandbox_Tutorial_909::isAllowedURL();
	 * @param string $url
	 * @return bool
	 */
	public static function isAllowedURL($url) {
		if (empty($url) || !defined('WPSANDBOX_TUTORIAL_909_ALLOWED_DOMAINS')) {
			return false;
		}

		$found = false;

		foreach (WPSANDBOX_TUTORIAL_909_ALLOWED_DOMAINS as $domain) {
			if (strpos($url, $domain) !== false) {
				$found = true;
				break;
			}
		}

		if (!$found) {
			return false;
		}

		$allowed_domains_esc = array_map('preg_quote', WPSANDBOX_TUTORIAL_909_ALLOWED_DOMAINS);
		$domains_ext_partial_regex = join('|', $allowed_domains_esc);

		if (preg_match('/(' . $domains_ext_partial_regex . ')/si', $url)) {
			return true;
		}

		return false;
	}

	/**
	 * WPSandbox_Tutorial_909::sendCORSHeaders();
	 *  An example CORS-compliant method.  It will allow any GET, POST, or OPTIONS requests from any
	 *  origin.
	 *
	 *  In a production environment, you probably want to be more restrictive, but this gives you
	 *  the general idea of what is involved.  For the nitty-gritty low-down, read:
	 *
	 *  - https://developer.mozilla.org/en/HTTP_access_control
	 *  - https://fetch.spec.whatwg.org/#http-cors-protocol
	 */
	public static function sendCORSHeaders() {
		if ( headers_sent() ) {
			return;
		}

		// Allow from any origin
		if (isset($_SERVER['HTTP_ORIGIN'])) {
			if (WPSandbox_Tutorial_909::isAllowedURL($_SERVER['HTTP_ORIGIN'])) {
				// Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
				// you want to allow, and if so:
				header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
				header('Access-Control-Allow-Credentials: true');
				header('Access-Control-Max-Age: 86400');    // cache for 1 day
			}
		}

		// Access-Control headers are received during OPTIONS requests
		if (!empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
			if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
				// may also be using PUT, PATCH, HEAD etc
				header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
			}

			if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
				header( "Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}" );
			} else {
				header( "Access-Control-Allow-Headers: X-Requested-With, token, Content-Type, Authorization" );
			}

			exit(0); // noo need to process any further for OPTIONS request
		}
	}
}

Benefits of CORS:

  1. Security: By specifying which domains can access your resources, CORS helps maintain the security integrity of your application.
  2. Flexibility: CORS provides a flexible and efficient way to handle cross-origin requests, essential for APIs and web services consumed by various clients, including mobile apps and web pages from different domains.
  3. Performance: With CORS, you can utilize resources across domains without resorting to less efficient workarounds like JSONP or proxy servers, leading to better performance and user experience.

Conclusion

Embracing CORS in your PHP applications is not just about enhancing functionality; it’s about doing so securely and efficiently. By understanding and properly implementing CORS headers, you enable your applications to interact seamlessly across different domains, thereby breaking down the barriers imposed by the same-origin policy. Remember, the goal is to maintain a balance between openness and security—allowing your applications to be as interactive and resourceful as they need to be, without exposing them to unnecessary risks. With the insights and guidance provided in this article, you’re well on your way to mastering CORS in PHP, a small yet significant step toward building robust, secure, and interoperable web applications.

Leave a Comment

Your email address will not be published. Required fields are marked *