Σ(゚Д゚;≡;゚д゚)Σ(゚Д゚;≡;゚д゚)Σ(゚Д゚;≡;゚д゚)始,故人唐宰相鲁公,🆚开府南服,余以布衣从戎。明年,别公漳水湄。后明年,公以事过张睢阳庙及颜杲卿所尝往来处,悲歌慷慨,卒不负其言而从之游。今其诗具在,可考也。😭 HEX
HEX
Server: Apache
System: Linux webm006.cluster120.gra.hosting.ovh.net 6.18.39-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Tue Jul 21 12:03:15 CEST 2026 x86_64
User: studionolh (122383)
PHP: 7.3.33
Disabled: _dyuweyrj4,_dyuweyrj4r,dl
Upload Files
File: /home/s/t/u/studionolh/www/wp-includes/Requests/Cookie/reusable-blocks/automattic.tar
jetpack-autoloader/src/class-version-loader.php000064400000007664152333514310015673 0ustar00<?php
/* HEADER */ // phpcs:ignore

/**
 * This class loads other classes based on given parameters.
 */
class Version_Loader {

	/**
	 * The Version_Selector object.
	 *
	 * @var Version_Selector
	 */
	private $version_selector;

	/**
	 * A map of available classes and their version and file path.
	 *
	 * @var array
	 */
	private $classmap;

	/**
	 * A map of PSR-4 namespaces and their version and directory path.
	 *
	 * @var array
	 */
	private $psr4_map;

	/**
	 * A map of all the files that we should load.
	 *
	 * @var array
	 */
	private $filemap;

	/**
	 * The constructor.
	 *
	 * @param Version_Selector $version_selector The Version_Selector object.
	 * @param array            $classmap The verioned classmap to load using.
	 * @param array            $psr4_map The versioned PSR-4 map to load using.
	 * @param array            $filemap The versioned filemap to load.
	 */
	public function __construct( $version_selector, $classmap, $psr4_map, $filemap ) {
		$this->version_selector = $version_selector;
		$this->classmap         = $classmap;
		$this->psr4_map         = $psr4_map;
		$this->filemap          = $filemap;
	}

	/**
	 * Finds the file path for the given class.
	 *
	 * @param string $class_name The class to find.
	 *
	 * @return string|null $file_path The path to the file if found, null if no class was found.
	 */
	public function find_class_file( $class_name ) {
		$data = $this->select_newest_file(
			isset( $this->classmap[ $class_name ] ) ? $this->classmap[ $class_name ] : null,
			$this->find_psr4_file( $class_name )
		);
		if ( ! isset( $data ) ) {
			return null;
		}

		return $data['path'];
	}

	/**
	 * Load all of the files in the filemap.
	 */
	public function load_filemap() {
		if ( empty( $this->filemap ) ) {
			return;
		}

		foreach ( $this->filemap as $file_identifier => $file_data ) {
			if ( empty( $GLOBALS['__composer_autoload_files'][ $file_identifier ] ) ) {
				require_once $file_data['path'];

				$GLOBALS['__composer_autoload_files'][ $file_identifier ] = true;
			}
		}
	}

	/**
	 * Compares different class sources and returns the newest.
	 *
	 * @param array|null $classmap_data The classmap class data.
	 * @param array|null $psr4_data The PSR-4 class data.
	 *
	 * @return array|null $data
	 */
	private function select_newest_file( $classmap_data, $psr4_data ) {
		if ( ! isset( $classmap_data ) ) {
			return $psr4_data;
		} elseif ( ! isset( $psr4_data ) ) {
			return $classmap_data;
		}

		if ( $this->version_selector->is_version_update_required( $classmap_data['version'], $psr4_data['version'] ) ) {
			return $psr4_data;
		}

		return $classmap_data;
	}

	/**
	 * Finds the file for a given class in a PSR-4 namespace.
	 *
	 * @param string $class_name The class to find.
	 *
	 * @return array|null $data The version and path path to the file if found, null otherwise.
	 */
	private function find_psr4_file( $class_name ) {
		if ( ! isset( $this->psr4_map ) ) {
			return null;
		}

		// Don't bother with classes that have no namespace.
		$class_index = strrpos( $class_name, '\\' );
		if ( ! $class_index ) {
			return null;
		}
		$class_for_path = str_replace( '\\', '/', $class_name );

		// Search for the namespace by iteratively cutting off the last segment until
		// we find a match. This allows us to check the most-specific namespaces
		// first as well as minimize the amount of time spent looking.
		for (
			$class_namespace = substr( $class_name, 0, $class_index );
			! empty( $class_namespace );
			$class_namespace = substr( $class_namespace, 0, strrpos( $class_namespace, '\\' ) )
		) {
			$namespace = $class_namespace . '\\';
			if ( ! isset( $this->psr4_map[ $namespace ] ) ) {
				continue;
			}
			$data = $this->psr4_map[ $namespace ];

			foreach ( $data['path'] as $path ) {
				$path .= '/' . substr( $class_for_path, strlen( $namespace ) ) . '.php';
				if ( file_exists( $path ) ) {
					return array(
						'version' => $data['version'],
						'path'    => $path,
					);
				}
			}
		}

		return null;
	}
}
jetpack-autoloader/src/CustomAutoloaderPlugin.php000064400000014057152333514310016302 0ustar00<?php //phpcs:ignore WordPress.Files.FileName.NotHyphenatedLowercase
/**
 * Custom Autoloader Composer Plugin, hooks into composer events to generate the custom autoloader.
 *
 * @package automattic/jetpack-autoloader
 */

// phpcs:disable PHPCompatibility.Keywords.NewKeywords.t_useFound
// phpcs:disable PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound
// phpcs:disable PHPCompatibility.Keywords.NewKeywords.t_namespaceFound
// phpcs:disable WordPress.Files.FileName.NotHyphenatedLowercase
// phpcs:disable WordPress.Files.FileName.InvalidClassFileName
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase

namespace Automattic\Jetpack\Autoloader;

use Composer\Composer;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
use Composer\Script\Event;
use Composer\Script\ScriptEvents;

/**
 * Class CustomAutoloaderPlugin.
 *
 * @package automattic/jetpack-autoloader
 */
class CustomAutoloaderPlugin implements PluginInterface, EventSubscriberInterface {

	/**
	 * IO object.
	 *
	 * @var IOInterface IO object.
	 */
	private $io;

	/**
	 * Composer object.
	 *
	 * @var Composer Composer object.
	 */
	private $composer;

	/**
	 * Do nothing.
	 *
	 * @param Composer    $composer Composer object.
	 * @param IOInterface $io IO object.
	 */
	public function activate( Composer $composer, IOInterface $io ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
		$this->composer = $composer;
		$this->io       = $io;
	}

	/**
	 * Do nothing.
	 * phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
	 *
	 * @param Composer    $composer Composer object.
	 * @param IOInterface $io IO object.
	 */
	public function deactivate( Composer $composer, IOInterface $io ) {
		/*
		 * Intentionally left empty. This is a PluginInterface method.
		 * phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
		 */
	}

	/**
	 * Do nothing.
	 * phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
	 *
	 * @param Composer    $composer Composer object.
	 * @param IOInterface $io IO object.
	 */
	public function uninstall( Composer $composer, IOInterface $io ) {
		/*
		 * Intentionally left empty. This is a PluginInterface method.
		 * phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
		 */
	}

	/**
	 * Tell composer to listen for events and do something with them.
	 *
	 * @return array List of subscribed events.
	 */
	public static function getSubscribedEvents() {
		return array(
			ScriptEvents::POST_AUTOLOAD_DUMP => 'postAutoloadDump',
		);
	}

	/**
	 * Generate the custom autolaoder.
	 *
	 * @param Event $event Script event object.
	 */
	public function postAutoloadDump( Event $event ) {
		// When the autoloader is not required by the root package we don't want to execute it.
		// This prevents unwanted transitive execution that generates unused autoloaders or
		// at worst throws fatal executions.
		if ( ! $this->isRequiredByRoot() ) {
			return;
		}

		$config = $this->composer->getConfig();

		if ( 'vendor' !== $config->raw()['config']['vendor-dir'] ) {
			$this->io->writeError( "\n<error>An error occurred while generating the autoloader files:", true );
			$this->io->writeError( 'The project\'s composer.json or composer environment set a non-default vendor directory.', true );
			$this->io->writeError( 'The default composer vendor directory must be used.</error>', true );
			exit();
		}

		$installationManager = $this->composer->getInstallationManager();
		$repoManager         = $this->composer->getRepositoryManager();
		$localRepo           = $repoManager->getLocalRepository();
		$package             = $this->composer->getPackage();
		$optimize            = $event->getFlags()['optimize'];
		$suffix              = $this->determineSuffix();

		$generator = new AutoloadGenerator( $this->io );
		$generator->dump( $this->composer, $config, $localRepo, $package, $installationManager, 'composer', $optimize, $suffix );
		$this->generated = true;
	}

	/**
	 * Determine the suffix for the autoloader class.
	 *
	 * Reuses an existing suffix from vendor/autoload_packages.php or vendor/autoload.php if possible.
	 *
	 * @return string Suffix.
	 */
	private function determineSuffix() {
		$config     = $this->composer->getConfig();
		$vendorPath = $config->get( 'vendor-dir' );

		// Command line.
		$suffix = $config->get( 'autoloader-suffix' );
		if ( $suffix ) {
			return $suffix;
		}

		// Reuse our own suffix, if any.
		if ( is_readable( $vendorPath . '/autoload_packages.php' ) ) {
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
			$content = file_get_contents( $vendorPath . '/autoload_packages.php' );
			if ( preg_match( '/^namespace Automattic\\\\Jetpack\\\\Autoloader\\\\jp([^;\s]+);/m', $content, $match ) ) {
				return $match[1];
			}
		}

		// Reuse Composer's suffix, if any.
		if ( is_readable( $vendorPath . '/autoload.php' ) ) {
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
			$content = file_get_contents( $vendorPath . '/autoload.php' );
			if ( preg_match( '{ComposerAutoloaderInit([^:\s]+)::}', $content, $match ) ) {
				return $match[1];
			}
		}

		// Generate a random suffix.
		return md5( uniqid( '', true ) );
	}

	/**
	 * Checks to see whether or not the root package is the one that required the autoloader.
	 *
	 * @return bool
	 */
	private function isRequiredByRoot() {
		$package  = $this->composer->getPackage();
		$requires = $package->getRequires();
		if ( ! is_array( $requires ) ) {
			$requires = array();
		}
		$devRequires = $package->getDevRequires();
		if ( ! is_array( $devRequires ) ) {
			$devRequires = array();
		}
		$requires = array_merge( $requires, $devRequires );

		if ( empty( $requires ) ) {
			$this->io->writeError( "\n<error>The package is not required and this should never happen?</error>", true );
			exit();
		}

		foreach ( $requires as $require ) {
			if ( 'automattic/jetpack-autoloader' === $require->getTarget() ) {
				return true;
			}
		}

		return false;
	}
}
jetpack-autoloader/src/AutoloadFileWriter.php000064400000006211152333514310015367 0ustar00<?php // phpcs:ignore WordPress.Files.FileName
/**
 * Autoloader file writer.
 *
 * @package automattic/jetpack-autoloader
 */

// phpcs:disable WordPress.Files.FileName.InvalidClassFileName
// phpcs:disable WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
// phpcs:disable WordPress.NamingConventions.ValidVariableName.InterpolatedVariableNotSnakeCase
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
// phpcs:disable WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase
// phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_var_export
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_fopen
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_fwrite

namespace Automattic\Jetpack\Autoloader;

/**
 * Class AutoloadFileWriter.
 */
class AutoloadFileWriter {

	/**
	 * The file comment to use.
	 */
	const COMMENT = <<<AUTOLOADER_COMMENT
/**
 * This file was automatically generated by automattic/jetpack-autoloader.
 *
 * @package automattic/jetpack-autoloader
 */

AUTOLOADER_COMMENT;

	/**
	 * Copies autoloader files and replaces any placeholders in them.
	 *
	 * @param IOInterface|null $io An IO for writing to.
	 * @param string           $outDir The directory to place the autoloader files in.
	 * @param string           $suffix The suffix to use in the autoloader's namespace.
	 */
	public static function copyAutoloaderFiles( $io, $outDir, $suffix ) {
		$renameList = array(
			'autoload.php' => '../autoload_packages.php',
		);
		$ignoreList = array(
			'AutoloadGenerator.php',
			'AutoloadProcessor.php',
			'CustomAutoloaderPlugin.php',
			'ManifestGenerator.php',
			'AutoloadFileWriter.php',
		);

		// Copy all of the autoloader files.
		$files = scandir( __DIR__ );
		foreach ( $files as $file ) {
			// Only PHP files will be copied.
			if ( substr( $file, -4 ) !== '.php' ) {
				continue;
			}

			if ( in_array( $file, $ignoreList, true ) ) {
				continue;
			}

			$newFile = isset( $renameList[ $file ] ) ? $renameList[ $file ] : $file;
			$content = self::prepareAutoloaderFile( $file, $suffix );

			$written = file_put_contents( $outDir . '/' . $newFile, $content );
			if ( $io ) {
				if ( $written ) {
					$io->writeError( "  <info>Generated: $newFile</info>" );
				} else {
					$io->writeError( "  <error>Error: $newFile</error>" );
				}
			}
		}
	}

	/**
	 * Prepares an autoloader file to be written to the destination.
	 *
	 * @param String $filename a file to prepare.
	 * @param String $suffix   Unique suffix used in the namespace.
	 *
	 * @return string
	 */
	private static function prepareAutoloaderFile( $filename, $suffix ) {
		$header  = self::COMMENT;
		$header .= PHP_EOL;
		$header .= 'namespace Automattic\Jetpack\Autoloader\jp' . $suffix . ';';
		$header .= PHP_EOL . PHP_EOL;

		$sourceLoader  = fopen( __DIR__ . '/' . $filename, 'r' );
		$file_contents = stream_get_contents( $sourceLoader );
		return str_replace(
			'/* HEADER */',
			$header,
			$file_contents
		);
	}
}
jetpack-autoloader/src/class-container.php000064400000011157152333514310014714 0ustar00<?php
/* HEADER */ // phpcs:ignore

/**
 * This class manages the files and dependencies of the autoloader.
 */
class Container {

	/**
	 * Since each autoloader's class files exist within their own namespace we need a map to
	 * convert between the local class and a shared key. Note that no version checking is
	 * performed on these dependencies and the first autoloader to register will be the
	 * one that is utilized.
	 */
	const SHARED_DEPENDENCY_KEYS = array(
		Hook_Manager::class => 'Hook_Manager',
	);

	/**
	 * A map of all the dependencies we've registered with the container and created.
	 *
	 * @var array
	 */
	protected $dependencies;

	/**
	 * The constructor.
	 */
	public function __construct() {
		$this->dependencies = array();

		$this->register_shared_dependencies();
		$this->register_dependencies();
		$this->initialize_globals();
	}

	/**
	 * Gets a dependency out of the container.
	 *
	 * @param string $class The class to fetch.
	 *
	 * @return mixed
	 * @throws \InvalidArgumentException When a class that isn't registered with the container is fetched.
	 */
	public function get( $class ) {
		if ( ! isset( $this->dependencies[ $class ] ) ) {
			throw new \InvalidArgumentException( "Class '$class' is not registered with the container." );
		}

		return $this->dependencies[ $class ];
	}

	/**
	 * Registers all of the dependencies that are shared between all instances of the autoloader.
	 */
	private function register_shared_dependencies() {
		global $jetpack_autoloader_container_shared;
		if ( ! isset( $jetpack_autoloader_container_shared ) ) {
			$jetpack_autoloader_container_shared = array();
		}

		$key = self::SHARED_DEPENDENCY_KEYS[ Hook_Manager::class ];
		if ( ! isset( $jetpack_autoloader_container_shared[ $key ] ) ) {
			require_once __DIR__ . '/class-hook-manager.php';
			$jetpack_autoloader_container_shared[ $key ] = new Hook_Manager();
		}
		$this->dependencies[ Hook_Manager::class ] = &$jetpack_autoloader_container_shared[ $key ];
	}

	/**
	 * Registers all of the dependencies with the container.
	 */
	private function register_dependencies() {
		require_once __DIR__ . '/class-path-processor.php';
		$this->dependencies[ Path_Processor::class ] = new Path_Processor();

		require_once __DIR__ . '/class-plugin-locator.php';
		$this->dependencies[ Plugin_Locator::class ] = new Plugin_Locator(
			$this->get( Path_Processor::class )
		);

		require_once __DIR__ . '/class-version-selector.php';
		$this->dependencies[ Version_Selector::class ] = new Version_Selector();

		require_once __DIR__ . '/class-autoloader-locator.php';
		$this->dependencies[ Autoloader_Locator::class ] = new Autoloader_Locator(
			$this->get( Version_Selector::class )
		);

		require_once __DIR__ . '/class-php-autoloader.php';
		$this->dependencies[ PHP_Autoloader::class ] = new PHP_Autoloader();

		require_once __DIR__ . '/class-manifest-reader.php';
		$this->dependencies[ Manifest_Reader::class ] = new Manifest_Reader(
			$this->get( Version_Selector::class )
		);

		require_once __DIR__ . '/class-plugins-handler.php';
		$this->dependencies[ Plugins_Handler::class ] = new Plugins_Handler(
			$this->get( Plugin_Locator::class ),
			$this->get( Path_Processor::class )
		);

		require_once __DIR__ . '/class-autoloader-handler.php';
		$this->dependencies[ Autoloader_Handler::class ] = new Autoloader_Handler(
			$this->get( PHP_Autoloader::class ),
			$this->get( Hook_Manager::class ),
			$this->get( Manifest_Reader::class ),
			$this->get( Version_Selector::class )
		);

		require_once __DIR__ . '/class-latest-autoloader-guard.php';
		$this->dependencies[ Latest_Autoloader_Guard::class ] = new Latest_Autoloader_Guard(
			$this->get( Plugins_Handler::class ),
			$this->get( Autoloader_Handler::class ),
			$this->get( Autoloader_Locator::class )
		);

		// Register any classes that we will use elsewhere.
		require_once __DIR__ . '/class-version-loader.php';
		require_once __DIR__ . '/class-shutdown-handler.php';
	}

	/**
	 * Initializes any of the globals needed by the autoloader.
	 */
	private function initialize_globals() {
		/*
		 * This global was retired in version 2.9. The value is set to 'false' to maintain
		 * compatibility with older versions of the autoloader.
		 */
		global $jetpack_autoloader_including_latest;
		$jetpack_autoloader_including_latest = false;

		// Not all plugins can be found using the locator. In cases where a plugin loads the autoloader
		// but was not discoverable, we will record them in this array to track them as "active".
		global $jetpack_autoloader_activating_plugins_paths;
		if ( ! isset( $jetpack_autoloader_activating_plugins_paths ) ) {
			$jetpack_autoloader_activating_plugins_paths = array();
		}
	}
}
jetpack-autoloader/src/class-shutdown-handler.php000064400000005203152333514310016213 0ustar00<?php
/* HEADER */ // phpcs:ignore

/**
 * This class handles the shutdown of the autoloader.
 */
class Shutdown_Handler {

	/**
	 * The Plugins_Handler instance.
	 *
	 * @var Plugins_Handler
	 */
	private $plugins_handler;

	/**
	 * The plugins cached by this autoloader.
	 *
	 * @var string[]
	 */
	private $cached_plugins;

	/**
	 * Indicates whether or not this autoloader was included by another.
	 *
	 * @var bool
	 */
	private $was_included_by_autoloader;

	/**
	 * Constructor.
	 *
	 * @param Plugins_Handler $plugins_handler The Plugins_Handler instance to use.
	 * @param string[]        $cached_plugins The plugins cached by the autoloaer.
	 * @param bool            $was_included_by_autoloader Indicates whether or not the autoloader was included by another.
	 */
	public function __construct( $plugins_handler, $cached_plugins, $was_included_by_autoloader ) {
		$this->plugins_handler            = $plugins_handler;
		$this->cached_plugins             = $cached_plugins;
		$this->was_included_by_autoloader = $was_included_by_autoloader;
	}

	/**
	 * Handles the shutdown of the autoloader.
	 */
	public function __invoke() {
		// Don't save a broken cache if an error happens during some plugin's initialization.
		if ( ! did_action( 'plugins_loaded' ) ) {
			// Ensure that the cache is emptied to prevent consecutive failures if the cache is to blame.
			if ( ! empty( $this->cached_plugins ) ) {
				$this->plugins_handler->cache_plugins( array() );
			}

			return;
		}

		// Load the active plugins fresh since the list we pulled earlier might not contain
		// plugins that were activated but did not reset the autoloader. This happens
		// when a plugin is in the cache but not "active" when the autoloader loads.
		// We also want to make sure that plugins which are deactivating are not
		// considered "active" so that they will be removed from the cache now.
		try {
			$active_plugins = $this->plugins_handler->get_active_plugins( false, ! $this->was_included_by_autoloader );
		} catch ( \Exception $ex ) {
			// When the package is deleted before shutdown it will throw an exception.
			// In the event this happens we should erase the cache.
			if ( ! empty( $this->cached_plugins ) ) {
				$this->plugins_handler->cache_plugins( array() );
			}
			return;
		}

		// The paths should be sorted for easy comparisons with those loaded from the cache.
		// Note we don't need to sort the cached entries because they're already sorted.
		sort( $active_plugins );

		// We don't want to waste time saving a cache that hasn't changed.
		if ( $this->cached_plugins === $active_plugins ) {
			return;
		}

		$this->plugins_handler->cache_plugins( $active_plugins );
	}
}
jetpack-autoloader/src/class-path-processor.php000064400000012557152333514310015710 0ustar00<?php
/* HEADER */ // phpcs:ignore

/**
 * This class handles dealing with paths for the autoloader.
 */
class Path_Processor {
	/**
	 * Given a path this will replace any of the path constants with a token to represent it.
	 *
	 * @param string $path The path we want to process.
	 *
	 * @return string The tokenized path.
	 */
	public function tokenize_path_constants( $path ) {
		$path = wp_normalize_path( $path );

		$constants = $this->get_normalized_constants();
		foreach ( $constants as $constant => $constant_path ) {
			$len = strlen( $constant_path );
			if ( substr( $path, 0, $len ) !== $constant_path ) {
				continue;
			}

			return substr_replace( $path, '{{' . $constant . '}}', 0, $len );
		}

		return $path;
	}

	/**
	 * Given a path this will replace any of the path constant tokens with the expanded path.
	 *
	 * @param string $tokenized_path The path we want to process.
	 *
	 * @return string The expanded path.
	 */
	public function untokenize_path_constants( $tokenized_path ) {
		$tokenized_path = wp_normalize_path( $tokenized_path );

		$constants = $this->get_normalized_constants();
		foreach ( $constants as $constant => $constant_path ) {
			$constant = '{{' . $constant . '}}';

			$len = strlen( $constant );
			if ( substr( $tokenized_path, 0, $len ) !== $constant ) {
				continue;
			}

			return $this->get_real_path( substr_replace( $tokenized_path, $constant_path, 0, $len ) );
		}

		return $tokenized_path;
	}

	/**
	 * Given a file and an array of places it might be, this will find the absolute path and return it.
	 *
	 * @param string $file The plugin or theme file to resolve.
	 * @param array  $directories_to_check The directories we should check for the file if it isn't an absolute path.
	 *
	 * @return string|false Returns the absolute path to the directory, otherwise false.
	 */
	public function find_directory_with_autoloader( $file, $directories_to_check ) {
		$file = wp_normalize_path( $file );

		if ( ! $this->is_absolute_path( $file ) ) {
			$file = $this->find_absolute_plugin_path( $file, $directories_to_check );
			if ( ! isset( $file ) ) {
				return false;
			}
		}

		// We need the real path for consistency with __DIR__ paths.
		$file = $this->get_real_path( $file );

		// phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged
		$directory = @is_file( $file ) ? dirname( $file ) : $file;
		if ( ! @is_file( $directory . '/vendor/composer/jetpack_autoload_classmap.php' ) ) {
			return false;
		}
		// phpcs:enable WordPress.PHP.NoSilencedErrors.Discouraged

		return $directory;
	}

	/**
	 * Fetches an array of normalized paths keyed by the constant they came from.
	 *
	 * @return string[] The normalized paths keyed by the constant.
	 */
	private function get_normalized_constants() {
		$raw_constants = array(
			// Order the constants from most-specific to least-specific.
			'WP_PLUGIN_DIR',
			'WPMU_PLUGIN_DIR',
			'WP_CONTENT_DIR',
			'ABSPATH',
		);

		$constants = array();
		foreach ( $raw_constants as $raw ) {
			if ( ! defined( $raw ) ) {
				continue;
			}

			$path = wp_normalize_path( constant( $raw ) );
			if ( isset( $path ) ) {
				$constants[ $raw ] = $path;
			}
		}

		return $constants;
	}

	/**
	 * Indicates whether or not a path is absolute.
	 *
	 * @param string $path The path to check.
	 *
	 * @return bool True if the path is absolute, otherwise false.
	 */
	private function is_absolute_path( $path ) {
		if ( 0 === strlen( $path ) || '.' === $path[0] ) {
			return false;
		}

		// Absolute paths on Windows may begin with a drive letter.
		if ( preg_match( '/^[a-zA-Z]:[\/\\\\]/', $path ) ) {
			return true;
		}

		// A path starting with / or \ is absolute; anything else is relative.
		return ( '/' === $path[0] || '\\' === $path[0] );
	}

	/**
	 * Given a file and a list of directories to check, this method will try to figure out
	 * the absolute path to the file in question.
	 *
	 * @param string $normalized_path The normalized path to the plugin or theme file to resolve.
	 * @param array  $directories_to_check The directories we should check for the file if it isn't an absolute path.
	 *
	 * @return string|null The absolute path to the plugin file, otherwise null.
	 */
	private function find_absolute_plugin_path( $normalized_path, $directories_to_check ) {
		// We're only able to find the absolute path for plugin/theme PHP files.
		if ( ! is_string( $normalized_path ) || '.php' !== substr( $normalized_path, -4 ) ) {
			return null;
		}

		foreach ( $directories_to_check as $directory ) {
			$normalized_check = wp_normalize_path( trailingslashit( $directory ) ) . $normalized_path;
			// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
			if ( @is_file( $normalized_check ) ) {
				return $normalized_check;
			}
		}

		return null;
	}

	/**
	 * Given a path this will figure out the real path that we should be using.
	 *
	 * @param string $path The path to resolve.
	 *
	 * @return string The resolved path.
	 */
	private function get_real_path( $path ) {
		// We want to resolve symbolic links for consistency with __DIR__ paths.
		// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
		$real_path = @realpath( $path );
		if ( false === $real_path ) {
			// Let the autoloader deal with paths that don't exist.
			$real_path = $path;
		}

		// Using realpath will make it platform-specific so we must normalize it after.
		if ( $path !== $real_path ) {
			$real_path = wp_normalize_path( $real_path );
		}

		return $real_path;
	}
}
jetpack-autoloader/src/AutoloadGenerator.php000064400000033623152333514310015250 0ustar00<?php // phpcs:ignore WordPress.Files.FileName
/**
 * Autoloader Generator.
 *
 * @package automattic/jetpack-autoloader
 */

// phpcs:disable PHPCompatibility.Keywords.NewKeywords.t_useFound
// phpcs:disable PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound
// phpcs:disable PHPCompatibility.FunctionDeclarations.NewClosure.Found
// phpcs:disable PHPCompatibility.Keywords.NewKeywords.t_namespaceFound
// phpcs:disable PHPCompatibility.Keywords.NewKeywords.t_dirFound
// phpcs:disable WordPress.Files.FileName.InvalidClassFileName
// phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_var_export
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_fopen
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_fwrite
// phpcs:disable WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
// phpcs:disable WordPress.NamingConventions.ValidVariableName.InterpolatedVariableNotSnakeCase
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
// phpcs:disable WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase

namespace Automattic\Jetpack\Autoloader;

use Composer\Autoload\ClassMapGenerator;
use Composer\Composer;
use Composer\Config;
use Composer\Installer\InstallationManager;
use Composer\IO\IOInterface;
use Composer\Package\PackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Util\Filesystem;
use Composer\Util\PackageSorter;

/**
 * Class AutoloadGenerator.
 */
class AutoloadGenerator {

	/**
	 * The filesystem utility.
	 *
	 * @var Filesystem
	 */
	private $filesystem;

	/**
	 * Instantiate an AutoloadGenerator object.
	 *
	 * @param IOInterface $io IO object.
	 */
	public function __construct( IOInterface $io = null ) {
		$this->io         = $io;
		$this->filesystem = new Filesystem();
	}

	/**
	 * Dump the Jetpack autoloader files.
	 *
	 * @param Composer                     $composer The Composer object.
	 * @param Config                       $config Config object.
	 * @param InstalledRepositoryInterface $localRepo Installed Repository object.
	 * @param PackageInterface             $mainPackage Main Package object.
	 * @param InstallationManager          $installationManager Manager for installing packages.
	 * @param string                       $targetDir Path to the current target directory.
	 * @param bool                         $scanPsrPackages Whether or not PSR packages should be converted to a classmap.
	 * @param string                       $suffix The autoloader suffix.
	 */
	public function dump(
		Composer $composer,
		Config $config,
		InstalledRepositoryInterface $localRepo,
		PackageInterface $mainPackage,
		InstallationManager $installationManager,
		$targetDir,
		$scanPsrPackages = false,
		$suffix = null
	) {
		$this->filesystem->ensureDirectoryExists( $config->get( 'vendor-dir' ) );

		$packageMap = $composer->getAutoloadGenerator()->buildPackageMap( $installationManager, $mainPackage, $localRepo->getCanonicalPackages() );
		$autoloads  = $this->parseAutoloads( $packageMap, $mainPackage );

		// Convert the autoloads into a format that the manifest generator can consume more easily.
		$basePath           = $this->filesystem->normalizePath( realpath( getcwd() ) );
		$vendorPath         = $this->filesystem->normalizePath( realpath( $config->get( 'vendor-dir' ) ) );
		$processedAutoloads = $this->processAutoloads( $autoloads, $scanPsrPackages, $vendorPath, $basePath );
		unset( $packageMap, $autoloads );

		// Make sure none of the legacy files remain that can lead to problems with the autoloader.
		$this->removeLegacyFiles( $vendorPath );

		// Write all of the files now that we're done.
		$this->writeAutoloaderFiles( $vendorPath . '/jetpack-autoloader/', $suffix );
		$this->writeManifests( $vendorPath . '/' . $targetDir, $processedAutoloads );

		if ( ! $scanPsrPackages ) {
			$this->io->writeError( '<warning>You are generating an unoptimized autoloader. If this is a production build, consider using the -o option.</warning>' );
		}
	}

	/**
	 * Compiles an ordered list of namespace => path mappings
	 *
	 * @param  array            $packageMap  Array of array(package, installDir-relative-to-composer.json).
	 * @param  PackageInterface $mainPackage Main package instance.
	 *
	 * @return array The list of path mappings.
	 */
	public function parseAutoloads( array $packageMap, PackageInterface $mainPackage ) {
		$rootPackageMap = array_shift( $packageMap );

		$sortedPackageMap   = $this->sortPackageMap( $packageMap );
		$sortedPackageMap[] = $rootPackageMap;
		array_unshift( $packageMap, $rootPackageMap );

		$psr0     = $this->parseAutoloadsType( $packageMap, 'psr-0', $mainPackage );
		$psr4     = $this->parseAutoloadsType( $packageMap, 'psr-4', $mainPackage );
		$classmap = $this->parseAutoloadsType( array_reverse( $sortedPackageMap ), 'classmap', $mainPackage );
		$files    = $this->parseAutoloadsType( $sortedPackageMap, 'files', $mainPackage );

		krsort( $psr0 );
		krsort( $psr4 );

		return array(
			'psr-0'    => $psr0,
			'psr-4'    => $psr4,
			'classmap' => $classmap,
			'files'    => $files,
		);
	}

	/**
	 * Sorts packages by dependency weight
	 *
	 * Packages of equal weight retain the original order
	 *
	 * @param  array $packageMap The package map.
	 *
	 * @return array
	 */
	protected function sortPackageMap( array $packageMap ) {
		$packages = array();
		$paths    = array();

		foreach ( $packageMap as $item ) {
			list( $package, $path ) = $item;
			$name                   = $package->getName();
			$packages[ $name ]      = $package;
			$paths[ $name ]         = $path;
		}

		$sortedPackages = PackageSorter::sortPackages( $packages );

		$sortedPackageMap = array();

		foreach ( $sortedPackages as $package ) {
			$name               = $package->getName();
			$sortedPackageMap[] = array( $packages[ $name ], $paths[ $name ] );
		}

		return $sortedPackageMap;
	}

	/**
	 * Returns the file identifier.
	 *
	 * @param PackageInterface $package The package instance.
	 * @param string           $path The path.
	 */
	protected function getFileIdentifier( PackageInterface $package, $path ) {
		return md5( $package->getName() . ':' . $path );
	}

	/**
	 * Returns the path code for the given path.
	 *
	 * @param Filesystem $filesystem The filesystem instance.
	 * @param string     $basePath The base path.
	 * @param string     $vendorPath The vendor path.
	 * @param string     $path The path.
	 *
	 * @return string The path code.
	 */
	protected function getPathCode( Filesystem $filesystem, $basePath, $vendorPath, $path ) {
		if ( ! $filesystem->isAbsolutePath( $path ) ) {
			$path = $basePath . '/' . $path;
		}
		$path = $filesystem->normalizePath( $path );

		$baseDir = '';
		if ( 0 === strpos( $path . '/', $vendorPath . '/' ) ) {
			$path    = substr( $path, strlen( $vendorPath ) );
			$baseDir = '$vendorDir';

			if ( false !== $path ) {
				$baseDir .= ' . ';
			}
		} else {
			$path = $filesystem->normalizePath( $filesystem->findShortestPath( $basePath, $path, true ) );
			if ( ! $filesystem->isAbsolutePath( $path ) ) {
				$baseDir = '$baseDir . ';
				$path    = '/' . $path;
			}
		}

		if ( strpos( $path, '.phar' ) !== false ) {
			$baseDir = "'phar://' . " . $baseDir;
		}

		return $baseDir . ( ( false !== $path ) ? var_export( $path, true ) : '' );
	}

	/**
	 * This function differs from the composer parseAutoloadsType in that beside returning the path.
	 * It also return the path and the version of a package.
	 *
	 * Supports PSR-4, PSR-0, and classmap parsing.
	 *
	 * @param array            $packageMap Map of all the packages.
	 * @param string           $type Type of autoloader to use.
	 * @param PackageInterface $mainPackage Instance of the Package Object.
	 *
	 * @return array
	 */
	protected function parseAutoloadsType( array $packageMap, $type, PackageInterface $mainPackage ) {
		$autoloads = array();

		foreach ( $packageMap as $item ) {
			list($package, $installPath) = $item;
			$autoload                    = $package->getAutoload();

			if ( $package === $mainPackage ) {
				$autoload = array_merge_recursive( $autoload, $package->getDevAutoload() );
			}

			if ( null !== $package->getTargetDir() && $package !== $mainPackage ) {
				$installPath = substr( $installPath, 0, -strlen( '/' . $package->getTargetDir() ) );
			}

			if ( in_array( $type, array( 'psr-4', 'psr-0' ), true ) && isset( $autoload[ $type ] ) && is_array( $autoload[ $type ] ) ) {
				foreach ( $autoload[ $type ] as $namespace => $paths ) {
					$paths = is_array( $paths ) ? $paths : array( $paths );
					foreach ( $paths as $path ) {
						$relativePath              = empty( $installPath ) ? ( empty( $path ) ? '.' : $path ) : $installPath . '/' . $path;
						$autoloads[ $namespace ][] = array(
							'path'    => $relativePath,
							'version' => $package->getVersion(), // Version of the class comes from the package - should we try to parse it?
						);
					}
				}
			}

			if ( 'classmap' === $type && isset( $autoload['classmap'] ) && is_array( $autoload['classmap'] ) ) {
				foreach ( $autoload['classmap'] as $paths ) {
					$paths = is_array( $paths ) ? $paths : array( $paths );
					foreach ( $paths as $path ) {
						$relativePath = empty( $installPath ) ? ( empty( $path ) ? '.' : $path ) : $installPath . '/' . $path;
						$autoloads[]  = array(
							'path'    => $relativePath,
							'version' => $package->getVersion(), // Version of the class comes from the package - should we try to parse it?
						);
					}
				}
			}
			if ( 'files' === $type && isset( $autoload['files'] ) && is_array( $autoload['files'] ) ) {
				foreach ( $autoload['files'] as $paths ) {
					$paths = is_array( $paths ) ? $paths : array( $paths );
					foreach ( $paths as $path ) {
						$relativePath = empty( $installPath ) ? ( empty( $path ) ? '.' : $path ) : $installPath . '/' . $path;
						$autoloads[ $this->getFileIdentifier( $package, $path ) ] = array(
							'path'    => $relativePath,
							'version' => $package->getVersion(), // Version of the file comes from the package - should we try to parse it?
						);
					}
				}
			}
		}

		return $autoloads;
	}

	/**
	 * Given Composer's autoloads this will convert them to a version that we can use to generate the manifests.
	 *
	 * When the $scanPsrPackages argument is true, PSR-4 namespaces are converted to classmaps. When $scanPsrPackages
	 * is false, PSR-4 namespaces are not converted to classmaps.
	 *
	 * PSR-0 namespaces are always converted to classmaps.
	 *
	 * @param array  $autoloads The autoloads we want to process.
	 * @param bool   $scanPsrPackages Whether or not PSR-4 packages should be converted to a classmap.
	 * @param string $vendorPath The path to the vendor directory.
	 * @param string $basePath The path to the current directory.
	 *
	 * @return array $processedAutoloads
	 */
	private function processAutoloads( $autoloads, $scanPsrPackages, $vendorPath, $basePath ) {
		$processor = new AutoloadProcessor(
			function ( $path, $excludedClasses, $namespace ) use ( $basePath ) {
				$dir = $this->filesystem->normalizePath(
					$this->filesystem->isAbsolutePath( $path ) ? $path : $basePath . '/' . $path
				);
				return ClassMapGenerator::createMap(
					$dir,
					$excludedClasses,
					null, // Don't pass the IOInterface since the normal autoload generation will have reported already.
					empty( $namespace ) ? null : $namespace
				);
			},
			function ( $path ) use ( $basePath, $vendorPath ) {
				return $this->getPathCode( $this->filesystem, $basePath, $vendorPath, $path );
			}
		);

		return array(
			'psr-4'    => $processor->processPsr4Packages( $autoloads, $scanPsrPackages ),
			'classmap' => $processor->processClassmap( $autoloads, $scanPsrPackages ),
			'files'    => $processor->processFiles( $autoloads ),
		);
	}

	/**
	 * Removes all of the legacy autoloader files so they don't cause any problems.
	 *
	 * @param string $outDir The directory legacy files are written to.
	 */
	private function removeLegacyFiles( $outDir ) {
		$files = array(
			'autoload_functions.php',
			'class-autoloader-handler.php',
			'class-classes-handler.php',
			'class-files-handler.php',
			'class-plugins-handler.php',
			'class-version-selector.php',
		);
		foreach ( $files as $file ) {
			$this->filesystem->remove( $outDir . '/' . $file );
		}
	}

	/**
	 * Writes all of the autoloader files to disk.
	 *
	 * @param string $outDir The directory to write to.
	 * @param string $suffix The unique autoloader suffix.
	 */
	private function writeAutoloaderFiles( $outDir, $suffix ) {
		$this->io->writeError( "<info>Generating jetpack autoloader ($outDir)</info>" );

		// We will remove all autoloader files to generate this again.
		$this->filesystem->emptyDirectory( $outDir );

		// Write the autoloader files.
		AutoloadFileWriter::copyAutoloaderFiles( $this->io, $outDir, $suffix );
	}

	/**
	 * Writes all of the manifest files to disk.
	 *
	 * @param string $outDir The directory to write to.
	 * @param array  $processedAutoloads The processed autoloads.
	 */
	private function writeManifests( $outDir, $processedAutoloads ) {
		$this->io->writeError( "<info>Generating jetpack autoloader manifests ($outDir)</info>" );

		$manifestFiles = array(
			'classmap' => 'jetpack_autoload_classmap.php',
			'psr-4'    => 'jetpack_autoload_psr4.php',
			'files'    => 'jetpack_autoload_filemap.php',
		);

		foreach ( $manifestFiles as $key => $file ) {
			// Make sure the file doesn't exist so it isn't there if we don't write it.
			$this->filesystem->remove( $outDir . '/' . $file );
			if ( empty( $processedAutoloads[ $key ] ) ) {
				continue;
			}

			$content = ManifestGenerator::buildManifest( $key, $file, $processedAutoloads[ $key ] );
			if ( empty( $content ) ) {
				continue;
			}

			if ( file_put_contents( $outDir . '/' . $file, $content ) ) {
				$this->io->writeError( "  <info>Generated: $file</info>" );
			} else {
				$this->io->writeError( "  <error>Error: $file</error>" );
			}
		}
	}
}
jetpack-autoloader/src/class-version-selector.php000064400000003165152333514310016235 0ustar00<?php
/* HEADER */ // phpcs:ignore

/**
 * Used to select package versions.
 */
class Version_Selector {

	/**
	 * Checks whether the selected package version should be updated. Composer development
	 * package versions ('9999999-dev' or versions that start with 'dev-') are favored
	 * when the JETPACK_AUTOLOAD_DEV constant is set to true.
	 *
	 * @param String $selected_version The currently selected package version.
	 * @param String $compare_version The package version that is being evaluated to
	 *                                determine if the version needs to be updated.
	 *
	 * @return bool Returns true if the selected package version should be updated,
	 *                 else false.
	 */
	public function is_version_update_required( $selected_version, $compare_version ) {
		$use_dev_versions = defined( 'JETPACK_AUTOLOAD_DEV' ) && JETPACK_AUTOLOAD_DEV;

		if ( is_null( $selected_version ) ) {
			return true;
		}

		if ( $use_dev_versions && $this->is_dev_version( $selected_version ) ) {
			return false;
		}

		if ( $this->is_dev_version( $compare_version ) ) {
			if ( $use_dev_versions ) {
				return true;
			} else {
				return false;
			}
		}

		if ( version_compare( $selected_version, $compare_version, '<' ) ) {
			return true;
		}

		return false;
	}

	/**
	 * Checks whether the given package version is a development version.
	 *
	 * @param String $version The package version.
	 *
	 * @return bool True if the version is a dev version, else false.
	 */
	public function is_dev_version( $version ) {
		if ( 'dev-' === substr( $version, 0, 4 ) || '9999999-dev' === $version ) {
			return true;
		}

		return false;
	}
}
jetpack-autoloader/src/AutoloadProcessor.php000064400000012357152333514310015302 0ustar00<?php // phpcs:ignore WordPress.Files.FileName
/**
 * Autoload Processor.
 *
 * @package automattic/jetpack-autoloader
 */

// phpcs:disable WordPress.Files.FileName.InvalidClassFileName
// phpcs:disable WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
// phpcs:disable WordPress.NamingConventions.ValidVariableName.InterpolatedVariableNotSnakeCase
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
// phpcs:disable WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase

namespace Automattic\Jetpack\Autoloader;

/**
 * Class AutoloadProcessor.
 */
class AutoloadProcessor {

	/**
	 * A callable for scanning a directory for all of its classes.
	 *
	 * @var callable
	 */
	private $classmapScanner;

	/**
	 * A callable for transforming a path into one to be used in code.
	 *
	 * @var callable
	 */
	private $pathCodeTransformer;

	/**
	 * The constructor.
	 *
	 * @param callable $classmapScanner A callable for scanning a directory for all of its classes.
	 * @param callable $pathCodeTransformer A callable for transforming a path into one to be used in code.
	 */
	public function __construct( $classmapScanner, $pathCodeTransformer ) {
		$this->classmapScanner     = $classmapScanner;
		$this->pathCodeTransformer = $pathCodeTransformer;
	}

	/**
	 * Processes the classmap autoloads into a relative path format including the version for each file.
	 *
	 * @param array $autoloads The autoloads we are processing.
	 * @param bool  $scanPsrPackages Whether or not PSR packages should be converted to a classmap.
	 *
	 * @return array $processed
	 */
	public function processClassmap( $autoloads, $scanPsrPackages ) {
		// We can't scan PSR packages if we don't actually have any.
		if ( empty( $autoloads['psr-4'] ) ) {
			$scanPsrPackages = false;
		}

		if ( empty( $autoloads['classmap'] ) && ! $scanPsrPackages ) {
			return null;
		}

		$excludedClasses = null;
		if ( ! empty( $autoloads['exclude-from-classmap'] ) ) {
			$excludedClasses = '{(' . implode( '|', $autoloads['exclude-from-classmap'] ) . ')}';
		}

		$processed = array();

		if ( $scanPsrPackages ) {
			foreach ( $autoloads['psr-4'] as $namespace => $sources ) {
				$namespace = empty( $namespace ) ? null : $namespace;

				foreach ( $sources as $source ) {
					$classmap = call_user_func( $this->classmapScanner, $source['path'], $excludedClasses, $namespace );

					foreach ( $classmap as $class => $path ) {
						$processed[ $class ] = array(
							'version' => $source['version'],
							'path'    => call_user_func( $this->pathCodeTransformer, $path ),
						);
					}
				}
			}
		}

		/*
		 * PSR-0 namespaces are converted to classmaps for both optimized and unoptimized autoloaders because any new
		 * development should use classmap or PSR-4 autoloading.
		 */
		if ( ! empty( $autoloads['psr-0'] ) ) {
			foreach ( $autoloads['psr-0'] as $namespace => $sources ) {
				$namespace = empty( $namespace ) ? null : $namespace;

				foreach ( $sources as $source ) {
					$classmap = call_user_func( $this->classmapScanner, $source['path'], $excludedClasses, $namespace );
					foreach ( $classmap as $class => $path ) {
						$processed[ $class ] = array(
							'version' => $source['version'],
							'path'    => call_user_func( $this->pathCodeTransformer, $path ),
						);
					}
				}
			}
		}

		if ( ! empty( $autoloads['classmap'] ) ) {
			foreach ( $autoloads['classmap'] as $package ) {
				$classmap = call_user_func( $this->classmapScanner, $package['path'], $excludedClasses, null );

				foreach ( $classmap as $class => $path ) {
					$processed[ $class ] = array(
						'version' => $package['version'],
						'path'    => call_user_func( $this->pathCodeTransformer, $path ),
					);
				}
			}
		}

		return $processed;
	}

	/**
	 * Processes the PSR-4 autoloads into a relative path format including the version for each file.
	 *
	 * @param array $autoloads The autoloads we are processing.
	 * @param bool  $scanPsrPackages Whether or not PSR packages should be converted to a classmap.
	 *
	 * @return array $processed
	 */
	public function processPsr4Packages( $autoloads, $scanPsrPackages ) {
		if ( $scanPsrPackages || empty( $autoloads['psr-4'] ) ) {
			return null;
		}

		$processed = array();

		foreach ( $autoloads['psr-4'] as $namespace => $packages ) {
			$namespace = empty( $namespace ) ? null : $namespace;
			$paths     = array();

			foreach ( $packages as $package ) {
				$paths[] = call_user_func( $this->pathCodeTransformer, $package['path'] );
			}

			$processed[ $namespace ] = array(
				'version' => $package['version'],
				'path'    => $paths,
			);
		}

		return $processed;
	}

	/**
	 * Processes the file autoloads into a relative format including the version for each file.
	 *
	 * @param array $autoloads The autoloads we are processing.
	 *
	 * @return array|null $processed
	 */
	public function processFiles( $autoloads ) {
		if ( empty( $autoloads['files'] ) ) {
			return null;
		}

		$processed = array();

		foreach ( $autoloads['files'] as $file_id => $package ) {
			$processed[ $file_id ] = array(
				'version' => $package['version'],
				'path'    => call_user_func( $this->pathCodeTransformer, $package['path'] ),
			);
		}

		return $processed;
	}
}
jetpack-autoloader/src/autoload.php000064400000000173152333514310013433 0ustar00<?php
/* HEADER */ // phpcs:ignore

require_once __DIR__ . '/jetpack-autoloader/class-autoloader.php';
Autoloader::init();
jetpack-autoloader/src/class-plugin-locator.php000064400000010174152333514310015667 0ustar00<?php
/* HEADER */ // phpcs:ignore

/**
 * This class scans the WordPress installation to find active plugins.
 */
class Plugin_Locator {

	/**
	 * The path processor for finding plugin paths.
	 *
	 * @var Path_Processor
	 */
	private $path_processor;

	/**
	 * The constructor.
	 *
	 * @param Path_Processor $path_processor The Path_Processor instance.
	 */
	public function __construct( $path_processor ) {
		$this->path_processor = $path_processor;
	}

	/**
	 * Finds the path to the current plugin.
	 *
	 * @return string $path The path to the current plugin.
	 *
	 * @throws \RuntimeException If the current plugin does not have an autoloader.
	 */
	public function find_current_plugin() {
		// Escape from `vendor/__DIR__` to root plugin directory.
		$plugin_directory = dirname( dirname( __DIR__ ) );

		// Use the path processor to ensure that this is an autoloader we're referencing.
		$path = $this->path_processor->find_directory_with_autoloader( $plugin_directory, array() );
		if ( false === $path ) {
			throw new \RuntimeException( 'Failed to locate plugin ' . $plugin_directory );
		}

		return $path;
	}

	/**
	 * Checks a given option for plugin paths.
	 *
	 * @param string $option_name  The option that we want to check for plugin information.
	 * @param bool   $site_option  Indicates whether or not we want to check the site option.
	 *
	 * @return array $plugin_paths The list of absolute paths we've found.
	 */
	public function find_using_option( $option_name, $site_option = false ) {
		$raw = $site_option ? get_site_option( $option_name ) : get_option( $option_name );
		if ( false === $raw ) {
			return array();
		}

		return $this->convert_plugins_to_paths( $raw );
	}

	/**
	 * Checks for plugins in the `action` request parameter.
	 *
	 * @param string[] $allowed_actions The actions that we're allowed to return plugins for.
	 *
	 * @return array $plugin_paths The list of absolute paths we've found.
	 */
	public function find_using_request_action( $allowed_actions ) {
		// phpcs:disable WordPress.Security.NonceVerification.Recommended

		/**
		 * Note: we're not actually checking the nonce here because it's too early
		 * in the execution. The pluggable functions are not yet loaded to give
		 * plugins a chance to plug their versions. Therefore we're doing the bare
		 * minimum: checking whether the nonce exists and it's in the right place.
		 * The request will fail later if the nonce doesn't pass the check.
		 */
		if ( empty( $_REQUEST['_wpnonce'] ) ) {
			return array();
		}

		$action = isset( $_REQUEST['action'] ) ? wp_unslash( $_REQUEST['action'] ) : false;
		if ( ! in_array( $action, $allowed_actions, true ) ) {
			return array();
		}

		$plugin_slugs = array();
		switch ( $action ) {
			case 'activate':
			case 'deactivate':
				if ( empty( $_REQUEST['plugin'] ) ) {
					break;
				}

				$plugin_slugs[] = wp_unslash( $_REQUEST['plugin'] );
				break;

			case 'activate-selected':
			case 'deactivate-selected':
				if ( empty( $_REQUEST['checked'] ) ) {
					break;
				}

				$plugin_slugs = wp_unslash( $_REQUEST['checked'] );
				break;
		}

		// phpcs:enable WordPress.Security.NonceVerification.Recommended
		return $this->convert_plugins_to_paths( $plugin_slugs );
	}

	/**
	 * Given an array of plugin slugs or paths, this will convert them to absolute paths and filter
	 * out the plugins that are not directory plugins. Note that array keys will also be included
	 * if they are plugin paths!
	 *
	 * @param string[] $plugins Plugin paths or slugs to filter.
	 *
	 * @return string[]
	 */
	private function convert_plugins_to_paths( $plugins ) {
		if ( ! is_array( $plugins ) || empty( $plugins ) ) {
			return array();
		}

		// We're going to look for plugins in the standard directories.
		$path_constants = array( WP_PLUGIN_DIR, WPMU_PLUGIN_DIR );

		$plugin_paths = array();
		foreach ( $plugins as $key => $value ) {
			$path = $this->path_processor->find_directory_with_autoloader( $key, $path_constants );
			if ( $path ) {
				$plugin_paths[] = $path;
			}

			$path = $this->path_processor->find_directory_with_autoloader( $value, $path_constants );
			if ( $path ) {
				$plugin_paths[] = $path;
			}
		}

		return $plugin_paths;
	}
}
jetpack-autoloader/src/class-plugins-handler.php000064400000013071152333514310016023 0ustar00<?php
/* HEADER */ // phpcs:ignore

/**
 * This class handles locating and caching all of the active plugins.
 */
class Plugins_Handler {
	/**
	 * The transient key for plugin paths.
	 */
	const TRANSIENT_KEY = 'jetpack_autoloader_plugin_paths';

	/**
	 * The locator for finding plugins in different locations.
	 *
	 * @var Plugin_Locator
	 */
	private $plugin_locator;

	/**
	 * The processor for transforming cached paths.
	 *
	 * @var Path_Processor
	 */
	private $path_processor;

	/**
	 * The constructor.
	 *
	 * @param Plugin_Locator $plugin_locator The locator for finding active plugins.
	 * @param Path_Processor $path_processor The processor for transforming cached paths.
	 */
	public function __construct( $plugin_locator, $path_processor ) {
		$this->plugin_locator = $plugin_locator;
		$this->path_processor = $path_processor;
	}

	/**
	 * Gets all of the active plugins we can find.
	 *
	 * @param bool $include_deactivating When true, plugins deactivating this request will be considered active.
	 * @param bool $record_unknown When true, the current plugin will be marked as active and recorded when unknown.
	 *
	 * @return string[]
	 */
	public function get_active_plugins( $include_deactivating, $record_unknown ) {
		global $jetpack_autoloader_activating_plugins_paths;

		// We're going to build a unique list of plugins from a few different sources
		// to find all of our "active" plugins. While we need to return an integer
		// array, we're going to use an associative array internally to reduce
		// the amount of time that we're going to spend checking uniqueness
		// and merging different arrays together to form the output.
		$active_plugins = array();

		// Make sure that plugins which have activated this request are considered as "active" even though
		// they probably won't be present in any option.
		if ( is_array( $jetpack_autoloader_activating_plugins_paths ) ) {
			foreach ( $jetpack_autoloader_activating_plugins_paths as $path ) {
				$active_plugins[ $path ] = $path;
			}
		}

		// This option contains all of the plugins that have been activated.
		$plugins = $this->plugin_locator->find_using_option( 'active_plugins' );
		foreach ( $plugins as $path ) {
			$active_plugins[ $path ] = $path;
		}

		// This option contains all of the multisite plugins that have been activated.
		if ( is_multisite() ) {
			$plugins = $this->plugin_locator->find_using_option( 'active_sitewide_plugins', true );
			foreach ( $plugins as $path ) {
				$active_plugins[ $path ] = $path;
			}
		}

		// These actions contain plugins that are being activated/deactivated during this request.
		$plugins = $this->plugin_locator->find_using_request_action( array( 'activate', 'activate-selected', 'deactivate', 'deactivate-selected' ) );
		foreach ( $plugins as $path ) {
			$active_plugins[ $path ] = $path;
		}

		// When the current plugin isn't considered "active" there's a problem.
		// Since we're here, the plugin is active and currently being loaded.
		// We can support this case (mu-plugins and non-standard activation)
		// by adding the current plugin to the active list and marking it
		// as an unknown (activating) plugin. This also has the benefit
		// of causing a reset because the active plugins list has
		// been changed since it was saved in the global.
		$current_plugin = $this->plugin_locator->find_current_plugin();
		if ( $record_unknown && ! in_array( $current_plugin, $active_plugins, true ) ) {
			$active_plugins[ $current_plugin ]             = $current_plugin;
			$jetpack_autoloader_activating_plugins_paths[] = $current_plugin;
		}

		// When deactivating plugins aren't desired we should entirely remove them from the active list.
		if ( ! $include_deactivating ) {
			// These actions contain plugins that are being deactivated during this request.
			$plugins = $this->plugin_locator->find_using_request_action( array( 'deactivate', 'deactivate-selected' ) );
			foreach ( $plugins as $path ) {
				unset( $active_plugins[ $path ] );
			}
		}

		// Transform the array so that we don't have to worry about the keys interacting with other array types later.
		return array_values( $active_plugins );
	}

	/**
	 * Gets all of the cached plugins if there are any.
	 *
	 * @return string[]
	 */
	public function get_cached_plugins() {
		$cached = get_transient( self::TRANSIENT_KEY );
		if ( ! is_array( $cached ) || empty( $cached ) ) {
			return array();
		}

		// We need to expand the tokens to an absolute path for this webserver.
		return array_map( array( $this->path_processor, 'untokenize_path_constants' ), $cached );
	}

	/**
	 * Saves the plugin list to the cache.
	 *
	 * @param array $plugins The plugin list to save to the cache.
	 */
	public function cache_plugins( $plugins ) {
		// We store the paths in a tokenized form so that that webservers with different absolute paths don't break.
		$plugins = array_map( array( $this->path_processor, 'tokenize_path_constants' ), $plugins );

		set_transient( self::TRANSIENT_KEY, $plugins );
	}

	/**
	 * Checks to see whether or not the plugin list given has changed when compared to the
	 * shared `$jetpack_autoloader_cached_plugin_paths` global. This allows us to deal
	 * with cases where the active list may change due to filtering..
	 *
	 * @param string[] $plugins The plugins list to check against the global cache.
	 *
	 * @return bool True if the plugins have changed, otherwise false.
	 */
	public function have_plugins_changed( $plugins ) {
		global $jetpack_autoloader_cached_plugin_paths;

		if ( $jetpack_autoloader_cached_plugin_paths !== $plugins ) {
			$jetpack_autoloader_cached_plugin_paths = $plugins;
			return true;
		}

		return false;
	}
}
jetpack-autoloader/src/class-hook-manager.php000064400000003643152333514310015303 0ustar00<?php
/* HEADER */ // phpcs:ignore

/**
 * Allows the latest autoloader to register hooks that can be removed when the autoloader is reset.
 */
class Hook_Manager {

	/**
	 * An array containing all of the hooks that we've registered.
	 *
	 * @var array
	 */
	private $registered_hooks;

	/**
	 * The constructor.
	 */
	public function __construct() {
		$this->registered_hooks = array();
	}

	/**
	 * Adds an action to WordPress and registers it internally.
	 *
	 * @param string   $tag           The name of the action which is hooked.
	 * @param callable $callable      The function to call.
	 * @param int      $priority      Used to specify the priority of the action.
	 * @param int      $accepted_args Used to specify the number of arguments the callable accepts.
	 */
	public function add_action( $tag, $callable, $priority = 10, $accepted_args = 1 ) {
		$this->registered_hooks[ $tag ][] = array(
			'priority' => $priority,
			'callable' => $callable,
		);

		add_action( $tag, $callable, $priority, $accepted_args );
	}

	/**
	 * Adds a filter to WordPress and registers it internally.
	 *
	 * @param string   $tag           The name of the filter which is hooked.
	 * @param callable $callable      The function to call.
	 * @param int      $priority      Used to specify the priority of the filter.
	 * @param int      $accepted_args Used to specify the number of arguments the callable accepts.
	 */
	public function add_filter( $tag, $callable, $priority = 10, $accepted_args = 1 ) {
		$this->registered_hooks[ $tag ][] = array(
			'priority' => $priority,
			'callable' => $callable,
		);

		add_filter( $tag, $callable, $priority, $accepted_args );
	}

	/**
	 * Removes all of the registered hooks.
	 */
	public function reset() {
		foreach ( $this->registered_hooks as $tag => $hooks ) {
			foreach ( $hooks as $hook ) {
				remove_filter( $tag, $hook['callable'], $hook['priority'] );
			}
		}
		$this->registered_hooks = array();
	}
}
jetpack-autoloader/src/class-autoloader.php000064400000007573152333514310015100 0ustar00<?php
/* HEADER */ // phpcs:ignore

/**
 * This class handles management of the actual PHP autoloader.
 */
class Autoloader {

	/**
	 * Checks to see whether or not the autoloader should be initialized and then initializes it if so.
	 *
	 * @param Container|null $container The container we want to use for autoloader initialization. If none is given
	 *                                  then a container will be created automatically.
	 */
	public static function init( $container = null ) {
		// The container holds and manages the lifecycle of our dependencies
		// to make them easier to work with and increase flexibility.
		if ( ! isset( $container ) ) {
			require_once __DIR__ . '/class-container.php';
			$container = new Container();
		}

		// phpcs:disable Generic.Commenting.DocComment.MissingShort

		/** @var Autoloader_Handler $autoloader_handler */
		$autoloader_handler = $container->get( Autoloader_Handler::class );

		// If the autoloader is already initializing it means that it has included us as the latest.
		$was_included_by_autoloader = $autoloader_handler->is_initializing();

		/** @var Plugin_Locator $plugin_locator */
		$plugin_locator = $container->get( Plugin_Locator::class );

		/** @var Plugins_Handler $plugins_handler */
		$plugins_handler = $container->get( Plugins_Handler::class );

		// The current plugin is the one that we are attempting to initialize here.
		$current_plugin = $plugin_locator->find_current_plugin();

		// The active plugins are those that we were able to discover on the site. This list will not
		// include mu-plugins, those activated by code, or those who are hidden by filtering. We also
		// want to take care to not consider the current plugin unknown if it was included by an
		// autoloader. This avoids the case where a plugin will be marked "active" while deactivated
		// due to it having the latest autoloader.
		$active_plugins = $plugins_handler->get_active_plugins( true, ! $was_included_by_autoloader );

		// The cached plugins are all of those that were active or discovered by the autoloader during a previous request.
		// Note that it's possible this list will include plugins that have since been deactivated, but after a request
		// the cache should be updated and the deactivated plugins will be removed.
		$cached_plugins = $plugins_handler->get_cached_plugins();

		// We combine the active list and cached list to preemptively load classes for plugins that are
		// presently unknown but will be loaded during the request. While this may result in us considering packages in
		// deactivated plugins there shouldn't be any problems as a result and the eventual consistency is sufficient.
		$all_plugins = array_merge( $active_plugins, $cached_plugins );

		// In particular we also include the current plugin to address the case where it is the latest autoloader
		// but also unknown (and not cached). We don't want it in the active list because we don't know that it
		// is active but we need it in the all plugins list so that it is considered by the autoloader.
		$all_plugins[] = $current_plugin;

		// We require uniqueness in the array to avoid processing the same plugin more than once.
		$all_plugins = array_values( array_unique( $all_plugins ) );

		/** @var Latest_Autoloader_Guard $guard */
		$guard = $container->get( Latest_Autoloader_Guard::class );
		if ( $guard->should_stop_init( $current_plugin, $all_plugins, $was_included_by_autoloader ) ) {
			return;
		}

		// Initialize the autoloader using the handler now that we're ready.
		$autoloader_handler->activate_autoloader( $all_plugins );

		/** @var Hook_Manager $hook_manager */
		$hook_manager = $container->get( Hook_Manager::class );

		// Register a shutdown handler to clean up the autoloader.
		$hook_manager->add_action( 'shutdown', new Shutdown_Handler( $plugins_handler, $cached_plugins, $was_included_by_autoloader ) );

		// phpcs:enable Generic.Commenting.DocComment.MissingShort
	}
}
jetpack-autoloader/src/class-latest-autoloader-guard.php000064400000005062152333514310017461 0ustar00<?php
/* HEADER */ // phpcs:ignore

/**
 * This class ensures that we're only executing the latest autoloader.
 */
class Latest_Autoloader_Guard {

	/**
	 * The Plugins_Handler instance.
	 *
	 * @var Plugins_Handler
	 */
	private $plugins_handler;

	/**
	 * The Autoloader_Handler instance.
	 *
	 * @var Autoloader_Handler
	 */
	private $autoloader_handler;

	/**
	 * The Autoloader_locator instance.
	 *
	 * @var Autoloader_Locator
	 */
	private $autoloader_locator;

	/**
	 * The constructor.
	 *
	 * @param Plugins_Handler    $plugins_handler    The Plugins_Handler instance.
	 * @param Autoloader_Handler $autoloader_handler The Autoloader_Handler instance.
	 * @param Autoloader_Locator $autoloader_locator The Autoloader_Locator instance.
	 */
	public function __construct( $plugins_handler, $autoloader_handler, $autoloader_locator ) {
		$this->plugins_handler    = $plugins_handler;
		$this->autoloader_handler = $autoloader_handler;
		$this->autoloader_locator = $autoloader_locator;
	}

	/**
	 * Indicates whether or not the autoloader should be initialized. Note that this function
	 * has the side-effect of actually loading the latest autoloader in the event that this
	 * is not it.
	 *
	 * @param string   $current_plugin             The current plugin we're checking.
	 * @param string[] $plugins                    The active plugins to check for autoloaders in.
	 * @param bool     $was_included_by_autoloader Indicates whether or not this autoloader was included by another.
	 *
	 * @return bool True if we should stop initialization, otherwise false.
	 */
	public function should_stop_init( $current_plugin, $plugins, $was_included_by_autoloader ) {
		global $jetpack_autoloader_latest_version;

		// We need to reset the autoloader when the plugins change because
		// that means the autoloader was generated with a different list.
		if ( $this->plugins_handler->have_plugins_changed( $plugins ) ) {
			$this->autoloader_handler->reset_autoloader();
		}

		// When the latest autoloader has already been found we don't need to search for it again.
		// We should take care however because this will also trigger if the autoloader has been
		// included by an older one.
		if ( isset( $jetpack_autoloader_latest_version ) && ! $was_included_by_autoloader ) {
			return true;
		}

		$latest_plugin = $this->autoloader_locator->find_latest_autoloader( $plugins, $jetpack_autoloader_latest_version );
		if ( isset( $latest_plugin ) && $latest_plugin !== $current_plugin ) {
			require $this->autoloader_locator->get_autoloader_path( $latest_plugin );
			return true;
		}

		return false;
	}
}
jetpack-autoloader/src/class-php-autoloader.php000064400000005071152333514310015654 0ustar00<?php
/* HEADER */ // phpcs:ignore

/**
 * This class handles management of the actual PHP autoloader.
 */
class PHP_Autoloader {

	/**
	 * Registers the autoloader with PHP so that it can begin autoloading classes.
	 *
	 * @param Version_Loader $version_loader The class loader to use in the autoloader.
	 */
	public function register_autoloader( $version_loader ) {
		// Make sure no other autoloaders are registered.
		$this->unregister_autoloader();

		// Set the global so that it can be used to load classes.
		global $jetpack_autoloader_loader;
		$jetpack_autoloader_loader = $version_loader;

		// Ensure that the autoloader is first to avoid contention with others.
		spl_autoload_register( array( self::class, 'load_class' ), true, true );
	}

	/**
	 * Unregisters the active autoloader so that it will no longer autoload classes.
	 */
	public function unregister_autoloader() {
		// Remove any v2 autoloader that we've already registered.
		$autoload_chain = spl_autoload_functions();
		foreach ( $autoload_chain as $autoloader ) {
			// We can identify a v2 autoloader using the namespace.
			$namespace_check = null;

			// Functions are recorded as strings.
			if ( is_string( $autoloader ) ) {
				$namespace_check = $autoloader;
			} elseif ( is_array( $autoloader ) && is_string( $autoloader[0] ) ) {
				// Static method calls have the class as the first array element.
				$namespace_check = $autoloader[0];
			} else {
				// Since the autoloader has only ever been a function or a static method we don't currently need to check anything else.
				continue;
			}

			// Check for the namespace without the generated suffix.
			if ( 'Automattic\\Jetpack\\Autoloader\\jp' === substr( $namespace_check, 0, 32 ) ) {
				spl_autoload_unregister( $autoloader );
			}
		}

		// Clear the global now that the autoloader has been unregistered.
		global $jetpack_autoloader_loader;
		$jetpack_autoloader_loader = null;
	}

	/**
	 * Loads a class file if one could be found.
	 *
	 * Note: This function is static so that the autoloader can be easily unregistered. If
	 * it was a class method we would have to unwrap the object to check the namespace.
	 *
	 * @param string $class_name The name of the class to autoload.
	 *
	 * @return bool Indicates whether or not a class file was loaded.
	 */
	public static function load_class( $class_name ) {
		global $jetpack_autoloader_loader;
		if ( ! isset( $jetpack_autoloader_loader ) ) {
			return;
		}

		$file = $jetpack_autoloader_loader->find_class_file( $class_name );
		if ( ! isset( $file ) ) {
			return false;
		}

		require $file;
		return true;
	}
}
jetpack-autoloader/src/ManifestGenerator.php000064400000007132152333514310015242 0ustar00<?php // phpcs:ignore WordPress.Files.FileName
/**
 * Manifest Generator.
 *
 * @package automattic/jetpack-autoloader
 */

// phpcs:disable WordPress.Files.FileName.InvalidClassFileName
// phpcs:disable WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
// phpcs:disable WordPress.NamingConventions.ValidVariableName.InterpolatedVariableNotSnakeCase
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
// phpcs:disable WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase
// phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_var_export

namespace Automattic\Jetpack\Autoloader;

/**
 * Class ManifestGenerator.
 */
class ManifestGenerator {

	/**
	 * Builds a manifest file for the given autoloader type.
	 *
	 * @param string $autoloaderType The type of autoloader to build a manifest for.
	 * @param string $fileName The filename of the manifest.
	 * @param array  $content The manifest content to generate using.
	 *
	 * @return string|null $manifestFile
	 * @throws \InvalidArgumentException When an invalid autoloader type is given.
	 */
	public static function buildManifest( $autoloaderType, $fileName, $content ) {
		if ( empty( $content ) ) {
			return null;
		}

		switch ( $autoloaderType ) {
			case 'classmap':
			case 'files':
				return self::buildStandardManifest( $fileName, $content );
			case 'psr-4':
				return self::buildPsr4Manifest( $fileName, $content );
		}

		throw new \InvalidArgumentException( 'An invalid manifest type of ' . $autoloaderType . ' was passed!' );
	}

	/**
	 * Builds the contents for the standard manifest file.
	 *
	 * @param string $fileName The filename we are building.
	 * @param array  $manifestData The formatted data for the manifest.
	 *
	 * @return string|null $manifestFile
	 */
	private static function buildStandardManifest( $fileName, $manifestData ) {
		$fileContent = PHP_EOL;
		foreach ( $manifestData as $key => $data ) {
			$key          = var_export( $key, true );
			$versionCode  = var_export( $data['version'], true );
			$fileContent .= <<<MANIFEST_CODE
	$key => array(
		'version' => $versionCode,
		'path'    => {$data['path']}
	),
MANIFEST_CODE;
			$fileContent .= PHP_EOL;
		}

		return self::buildFile( $fileName, $fileContent );
	}

	/**
	 * Builds the contents for the PSR-4 manifest file.
	 *
	 * @param string $fileName The filename we are building.
	 * @param array  $namespaces The formatted PSR-4 data for the manifest.
	 *
	 * @return string|null $manifestFile
	 */
	private static function buildPsr4Manifest( $fileName, $namespaces ) {
		$fileContent = PHP_EOL;
		foreach ( $namespaces as $namespace => $data ) {
			$namespaceCode = var_export( $namespace, true );
			$versionCode   = var_export( $data['version'], true );
			$pathCode      = 'array( ' . implode( ', ', $data['path'] ) . ' )';
			$fileContent  .= <<<MANIFEST_CODE
	$namespaceCode => array(
		'version' => $versionCode,
		'path'    => $pathCode
	),
MANIFEST_CODE;
			$fileContent  .= PHP_EOL;
		}

		return self::buildFile( $fileName, $fileContent );
	}

	/**
	 * Generate the PHP that will be used in the file.
	 *
	 * @param string $fileName The filename we are building.
	 * @param string $content The content to be written into the file.
	 *
	 * @return string $fileContent
	 */
	private static function buildFile( $fileName, $content ) {
		return <<<INCLUDE_FILE
<?php

// This file `$fileName` was auto generated by automattic/jetpack-autoloader.

\$vendorDir = dirname(__DIR__);
\$baseDir   = dirname(\$vendorDir);

return array($content);

INCLUDE_FILE;
	}
}
jetpack-autoloader/src/class-autoloader-locator.php000064400000003616152333514310016533 0ustar00<?php
/* HEADER */ // phpcs:ignore

use Automattic\Jetpack\Autoloader\AutoloadGenerator;

/**
 * This class locates autoloaders.
 */
class Autoloader_Locator {

	/**
	 * The object for comparing autoloader versions.
	 *
	 * @var Version_Selector
	 */
	private $version_selector;

	/**
	 * The constructor.
	 *
	 * @param Version_Selector $version_selector The version selector object.
	 */
	public function __construct( $version_selector ) {
		$this->version_selector = $version_selector;
	}

	/**
	 * Finds the path to the plugin with the latest autoloader.
	 *
	 * @param array  $plugin_paths An array of plugin paths.
	 * @param string $latest_version The latest version reference.
	 *
	 * @return string|null
	 */
	public function find_latest_autoloader( $plugin_paths, &$latest_version ) {
		$latest_plugin = null;

		foreach ( $plugin_paths as $plugin_path ) {
			$version = $this->get_autoloader_version( $plugin_path );
			if ( ! $this->version_selector->is_version_update_required( $latest_version, $version ) ) {
				continue;
			}

			$latest_version = $version;
			$latest_plugin  = $plugin_path;
		}

		return $latest_plugin;
	}

	/**
	 * Gets the path to the autoloader.
	 *
	 * @param string $plugin_path The path to the plugin.
	 *
	 * @return string
	 */
	public function get_autoloader_path( $plugin_path ) {
		return trailingslashit( $plugin_path ) . 'vendor/autoload_packages.php';
	}

	/**
	 * Gets the version for the autoloader.
	 *
	 * @param string $plugin_path The path to the plugin.
	 *
	 * @return string|null
	 */
	public function get_autoloader_version( $plugin_path ) {
		$classmap = trailingslashit( $plugin_path ) . 'vendor/composer/jetpack_autoload_classmap.php';
		if ( ! file_exists( $classmap ) ) {
			return null;
		}

		$classmap = require $classmap;
		if ( isset( $classmap[ AutoloadGenerator::class ] ) ) {
			return $classmap[ AutoloadGenerator::class ]['version'];
		}

		return null;
	}
}
jetpack-autoloader/src/class-autoloader-handler.php000064400000010465152333514310016505 0ustar00<?php
/* HEADER */ // phpcs:ignore

use Automattic\Jetpack\Autoloader\AutoloadGenerator;

/**
 * This class selects the package version for the autoloader.
 */
class Autoloader_Handler {

	/**
	 * The PHP_Autoloader instance.
	 *
	 * @var PHP_Autoloader
	 */
	private $php_autoloader;

	/**
	 * The Hook_Manager instance.
	 *
	 * @var Hook_Manager
	 */
	private $hook_manager;

	/**
	 * The Manifest_Reader instance.
	 *
	 * @var Manifest_Reader
	 */
	private $manifest_reader;

	/**
	 * The Version_Selector instance.
	 *
	 * @var Version_Selector
	 */
	private $version_selector;

	/**
	 * The constructor.
	 *
	 * @param PHP_Autoloader   $php_autoloader The PHP_Autoloader instance.
	 * @param Hook_Manager     $hook_manager The Hook_Manager instance.
	 * @param Manifest_Reader  $manifest_reader The Manifest_Reader instance.
	 * @param Version_Selector $version_selector The Version_Selector instance.
	 */
	public function __construct( $php_autoloader, $hook_manager, $manifest_reader, $version_selector ) {
		$this->php_autoloader   = $php_autoloader;
		$this->hook_manager     = $hook_manager;
		$this->manifest_reader  = $manifest_reader;
		$this->version_selector = $version_selector;
	}

	/**
	 * Checks to see whether or not an autoloader is currently in the process of initializing.
	 *
	 * @return bool
	 */
	public function is_initializing() {
		// If no version has been set it means that no autoloader has started initializing yet.
		global $jetpack_autoloader_latest_version;
		if ( ! isset( $jetpack_autoloader_latest_version ) ) {
			return false;
		}

		// When the version is set but the classmap is not it ALWAYS means that this is the
		// latest autoloader and is being included by an older one.
		global $jetpack_packages_classmap;
		if ( empty( $jetpack_packages_classmap ) ) {
			return true;
		}

		// Version 2.4.0 added a new global and altered the reset semantics. We need to check
		// the other global as well since it may also point at initialization.
		// Note: We don't need to check for the class first because every autoloader that
		// will set the latest version global requires this class in the classmap.
		$replacing_version = $jetpack_packages_classmap[ AutoloadGenerator::class ]['version'];
		if ( $this->version_selector->is_dev_version( $replacing_version ) || version_compare( $replacing_version, '2.4.0.0', '>=' ) ) {
			global $jetpack_autoloader_loader;
			if ( ! isset( $jetpack_autoloader_loader ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Activates an autoloader using the given plugins and activates it.
	 *
	 * @param string[] $plugins The plugins to initialize the autoloader for.
	 */
	public function activate_autoloader( $plugins ) {
		global $jetpack_packages_psr4;
		$jetpack_packages_psr4 = array();
		$this->manifest_reader->read_manifests( $plugins, 'vendor/composer/jetpack_autoload_psr4.php', $jetpack_packages_psr4 );

		global $jetpack_packages_classmap;
		$jetpack_packages_classmap = array();
		$this->manifest_reader->read_manifests( $plugins, 'vendor/composer/jetpack_autoload_classmap.php', $jetpack_packages_classmap );

		global $jetpack_packages_filemap;
		$jetpack_packages_filemap = array();
		$this->manifest_reader->read_manifests( $plugins, 'vendor/composer/jetpack_autoload_filemap.php', $jetpack_packages_filemap );

		$loader = new Version_Loader(
			$this->version_selector,
			$jetpack_packages_classmap,
			$jetpack_packages_psr4,
			$jetpack_packages_filemap
		);

		$this->php_autoloader->register_autoloader( $loader );

		// Now that the autoloader is active we can load the filemap.
		$loader->load_filemap();
	}

	/**
	 * Resets the active autoloader and all related global state.
	 */
	public function reset_autoloader() {
		$this->php_autoloader->unregister_autoloader();
		$this->hook_manager->reset();

		// Clear all of the autoloader globals so that older autoloaders don't do anything strange.
		global $jetpack_autoloader_latest_version;
		$jetpack_autoloader_latest_version = null;

		global $jetpack_packages_classmap;
		$jetpack_packages_classmap = array(); // Must be array to avoid exceptions in old autoloaders!

		global $jetpack_packages_psr4;
		$jetpack_packages_psr4 = array(); // Must be array to avoid exceptions in old autoloaders!

		global $jetpack_packages_filemap;
		$jetpack_packages_filemap = array(); // Must be array to avoid exceptions in old autoloaders!
	}
}
jetpack-autoloader/src/class-manifest-reader.php000064400000004673152333514310016005 0ustar00<?php
/* HEADER */ // phpcs:ignore

/**
 * This class reads autoloader manifest files.
 */
class Manifest_Reader {

	/**
	 * The Version_Selector object.
	 *
	 * @var Version_Selector
	 */
	private $version_selector;

	/**
	 * The constructor.
	 *
	 * @param Version_Selector $version_selector The Version_Selector object.
	 */
	public function __construct( $version_selector ) {
		$this->version_selector = $version_selector;
	}

	/**
	 * Reads all of the manifests in the given plugin paths.
	 *
	 * @param array  $plugin_paths  The paths to the plugins we're loading the manifest in.
	 * @param string $manifest_path The path that we're loading the manifest from in each plugin.
	 * @param array  $path_map The path map to add the contents of the manifests to.
	 *
	 * @return array $path_map The path map we've built using the manifests in each plugin.
	 */
	public function read_manifests( $plugin_paths, $manifest_path, &$path_map ) {
		$file_paths = array_map(
			function ( $path ) use ( $manifest_path ) {
				return trailingslashit( $path ) . $manifest_path;
			},
			$plugin_paths
		);

		foreach ( $file_paths as $path ) {
			$this->register_manifest( $path, $path_map );
		}

		return $path_map;
	}

	/**
	 * Registers a plugin's manifest file with the path map.
	 *
	 * @param string $manifest_path The absolute path to the manifest that we're loading.
	 * @param array  $path_map The path map to add the contents of the manifest to.
	 */
	protected function register_manifest( $manifest_path, &$path_map ) {
		if ( ! is_readable( $manifest_path ) ) {
			return;
		}

		$manifest = require $manifest_path;
		if ( ! is_array( $manifest ) ) {
			return;
		}

		foreach ( $manifest as $key => $data ) {
			$this->register_record( $key, $data, $path_map );
		}
	}

	/**
	 * Registers an entry from the manifest in the path map.
	 *
	 * @param string $key The identifier for the entry we're registering.
	 * @param array  $data The data for the entry we're registering.
	 * @param array  $path_map The path map to add the contents of the manifest to.
	 */
	protected function register_record( $key, $data, &$path_map ) {
		if ( isset( $path_map[ $key ]['version'] ) ) {
			$selected_version = $path_map[ $key ]['version'];
		} else {
			$selected_version = null;
		}

		if ( $this->version_selector->is_version_update_required( $selected_version, $data['version'] ) ) {
			$path_map[ $key ] = array(
				'version' => $data['version'],
				'path'    => $data['path'],
			);
		}
	}
}
jetpack-constants/src/class-constants.php000064400000006452152333514310014625 0ustar00<?php
/**
 * A constants manager for Jetpack.
 *
 * @package automattic/jetpack-constants
 */

namespace Automattic\Jetpack;

/**
 * Class Automattic\Jetpack\Constants
 *
 * Testing constants is hard. Once you define a constant, it's defined. Constants Manager is an
 * abstraction layer so that unit tests can set "constants" for tests.
 *
 * To test your code, you'll need to swap out `defined( 'CONSTANT' )` with `Automattic\Jetpack\Constants::is_defined( 'CONSTANT' )`
 * and replace `CONSTANT` with `Automattic\Jetpack\Constants::get_constant( 'CONSTANT' )`. Then in the unit test, you can set the
 * constant with `Automattic\Jetpack\Constants::set_constant( 'CONSTANT', $value )` and then clean up after each test with something like
 * this:
 *
 * function tearDown() {
 *     Automattic\Jetpack\Constants::clear_constants();
 * }
 */
class Constants {
	/**
	 * A container for all defined constants.
	 *
	 * @access public
	 * @static
	 *
	 * @var array.
	 */
	public static $set_constants = array();

	/**
	 * Checks if a "constant" has been set in constants Manager
	 * and has the value of true
	 *
	 * @param string $name The name of the constant.
	 *
	 * @return bool
	 */
	public static function is_true( $name ) {
		return self::is_defined( $name ) && self::get_constant( $name );
	}

	/**
	 * Checks if a "constant" has been set in constants Manager, and if not,
	 * checks if the constant was defined with define( 'name', 'value ).
	 *
	 * @param string $name The name of the constant.
	 *
	 * @return bool
	 */
	public static function is_defined( $name ) {
		return array_key_exists( $name, self::$set_constants )
			? true
			: defined( $name );
	}

	/**
	 * Attempts to retrieve the "constant" from constants Manager, and if it hasn't been set,
	 * then attempts to get the constant with the constant() function. If that also hasn't
	 * been set, attempts to get a value from filters.
	 *
	 * @param string $name The name of the constant.
	 *
	 * @return mixed null if the constant does not exist or the value of the constant.
	 */
	public static function get_constant( $name ) {
		if ( array_key_exists( $name, self::$set_constants ) ) {
			return self::$set_constants[ $name ];
		}

		if ( defined( $name ) ) {
			return constant( $name );
		}

		/**
		 * Filters the value of the constant.
		 *
		 * @since 8.5.0
		 *
		 * @param null The constant value to be filtered. The default is null.
		 * @param String $name The constant name.
		 */
		return apply_filters( 'jetpack_constant_default_value', null, $name );
	}

	/**
	 * Sets the value of the "constant" within constants Manager.
	 *
	 * @param string $name The name of the constant.
	 * @param string $value The value of the constant.
	 */
	public static function set_constant( $name, $value ) {
		self::$set_constants[ $name ] = $value;
	}

	/**
	 * Will unset a "constant" from constants Manager if the constant exists.
	 *
	 * @param string $name The name of the constant.
	 *
	 * @return bool Whether the constant was removed.
	 */
	public static function clear_single_constant( $name ) {
		if ( ! array_key_exists( $name, self::$set_constants ) ) {
			return false;
		}

		unset( self::$set_constants[ $name ] );

		return true;
	}

	/**
	 * Resets all of the constants within constants Manager.
	 */
	public static function clear_constants() {
		self::$set_constants = array();
	}
}