$defined_set constant name => 1 */ $defined_set = array_flip( $def_matches[1] ?? [] ); if ( $verbose ) { echo 'Defined in ' . CONSTANTS_BOOTSTRAP_FILE . ' (' . count( $defined_set ) . "):\n"; foreach ( array_keys( $defined_set ) as $constant_name ) { echo " {$constant_name}\n"; } echo "\n"; } // ------------------------------------------------------------------------- // 2. Collect shipped PHP files to scan. // ------------------------------------------------------------------------- /** * Recursively collect *.php paths under a directory, skipping excluded dirs. * * @param string $dir Directory to walk. * @param string[] $files Accumulator (modified by reference). * @return void */ function constants_collect_php_files( string $dir, array &$files ): void { $dir_iter = new DirectoryIterator( $dir ); foreach ( $dir_iter as $entry ) { if ( $entry->isDot() ) { continue; } $basename = $entry->getBasename(); if ( $entry->isDir() ) { if ( ! in_array( $basename, CONSTANTS_EXCLUDE_DIRS, true ) ) { constants_collect_php_files( $entry->getPathname(), $files ); } continue; } if ( $entry->isFile() && $entry->getExtension() === 'php' ) { $files[] = $entry->getPathname(); } } } /** @var string[] $php_files */ $php_files = []; foreach ( CONSTANTS_SCAN_ROOTS as $root ) { if ( ! file_exists( $root ) ) { // Template dir may not exist in very early checkouts -- skip silently. continue; } if ( is_file( $root ) ) { $php_files[] = $root; } else { constants_collect_php_files( $root, $php_files ); } } sort( $php_files ); if ( $verbose ) { echo 'Scanning ' . count( $php_files ) . " PHP files\n\n"; } // ------------------------------------------------------------------------- // 3. Scan each file for bare PRAUTOBLOGGER_* references. // ------------------------------------------------------------------------- /** @var array $errors */ $errors = []; foreach ( $php_files as $php_path ) { $raw = file_get_contents( $php_path ); if ( $raw === false ) { fwrite( STDERR, "WARNING: cannot read {$php_path} -- skipping\n" ); continue; } $lines = explode( "\n", $raw ); foreach ( $lines as $idx => $raw_line ) { // Fast pre-check: skip lines with no PRAUTOBLOGGER_ token. if ( strpos( $raw_line, 'PRAUTOBLOGGER_' ) === false ) { continue; } // Skip pure comment lines (docblock * lines, // comments, # lines). $trimmed = ltrim( $raw_line ); if ( str_starts_with( $trimmed, '*' ) || str_starts_with( $trimmed, '//' ) || str_starts_with( $trimmed, '#' ) ) { continue; } // Extract all constant names from this line. if ( ! preg_match_all( '/PRAUTOBLOGGER_[A-Z0-9_]+/', $raw_line, $match ) ) { continue; } foreach ( $match[0] as $name ) { // Skip if this line is itself a define() call for this name. if ( preg_match( "/define\s*\(\s*'" . preg_quote( $name, '/' ) . "'/", $raw_line ) ) { continue; } // Skip if the constant is production-defined in prautoblogger.php. if ( isset( $defined_set[ $name ] ) ) { continue; } // Check for a defined() guard in the preceding GUARD_WINDOW lines // (inclusive of the current line to catch same-line chained &&). $window_start = max( 0, $idx - CONSTANTS_GUARD_WINDOW ); $guarded = false; for ( $w = $window_start; $w <= $idx; $w++ ) { if ( preg_match( "/defined\s*\(\s*'" . preg_quote( $name, '/' ) . "'/", $lines[ $w ] ) ) { $guarded = true; break; } } if ( ! $guarded ) { $errors[] = [ $php_path, $idx + 1, $name, $raw_line ]; } } } } // ------------------------------------------------------------------------- // 4. Report results. // ------------------------------------------------------------------------- if ( $errors !== [] ) { fwrite( STDERR, "\nFAIL -- Unguarded undefined PRAUTOBLOGGER_* constants:\n\n" ); foreach ( $errors as [ $php_path, $lineno, $name, $line_text ] ) { fwrite( STDERR, " {$php_path}:{$lineno}: {$name}\n" ); fwrite( STDERR, ' ' . trim( $line_text ) . "\n" ); } fwrite( STDERR, "\nTo fix: add define( '" . $errors[0][2] . "', ... ) to prautoblogger.php,\n" ); fwrite( STDERR, "or guard the reference with if ( defined( '" . $errors[0][2] . "' ) ) { ... }\n\n" ); exit( 1 ); } echo "OK -- All PRAUTOBLOGGER_* constants are production-defined or defined()-guarded.\n"; exit( 0 );