<?php
/**
 * PHP source recognition helpers.
 *
 * @package LocalGuardScanner
 */

namespace LocalGuardScanner\Detection\Php;

/**
 * Decides whether a candidate is worth tokenizing as PHP.
 *
 * Detectors used to look for the literal string `<?php`, which silently skipped
 * files whose only opening tag is `<?=` or a bare short tag. The check below is
 * purely lexical so that the decision does not depend on the runtime
 * `short_open_tag` setting of whichever process happens to run the scan.
 *
 * `token_get_all()` still honours `short_open_tag`, so a bare `<?` block is
 * tokenized as PHP only where PHP itself would execute it. Opening the gate
 * costs one extra tokenization on those files and never hides them.
 */
final class PhpSource {
	/**
	 * Whether the content contains a PHP opening tag.
	 *
	 * Recognizes `<?php`, `<?=` and a bare `<?` that is not the start of an XML
	 * or processing instruction declaration such as `<?xml`.
	 *
	 * @param mixed $content Candidate file content.
	 * @return bool
	 */
	public static function has_open_tag( $content ) {
		if ( ! is_string( $content ) || '' === $content ) {
			return false;
		}
		return 1 === preg_match( '/<\?(?:php\b|=|(?![a-z]))/i', $content );
	}
}
