$start, 'length' => $stop - $start, ); } /** * Whether the subject contains the block. * * @param string $subject Full file contents. * @param string $begin Opening marker line. * @param string $end Closing marker line. * @return bool True when present. */ public static function exists( string $subject, string $begin, string $end ): bool { return null !== self::locate( $subject, $begin, $end ); } /** * Replaces the block, or appends it when not already present. * * @param string $subject Full file contents. * @param string $begin Opening marker line. * @param string $end Closing marker line. * @param string $replacement The block to insert, including both markers. * @return string Updated contents. */ public static function replace( string $subject, string $begin, string $end, string $replacement ): string { $location = self::locate( $subject, $begin, $end ); if ( null === $location ) { if ( '' === $replacement ) { return $subject; } if ( '' === $subject ) { return $replacement; } $separator = "\n" === substr( $subject, -1 ) ? "\n" : "\n\n"; return $subject . $separator . $replacement; } return substr( $subject, 0, $location['start'] ) . $replacement . substr( $subject, $location['start'] + $location['length'] ); } /** * Removes the block, leaving everything else byte-identical. * * @param string $subject Full file contents. * @param string $begin Opening marker line. * @param string $end Closing marker line. * @return string Updated contents. */ public static function remove( string $subject, string $begin, string $end ): string { $location = self::locate( $subject, $begin, $end ); if ( null === $location ) { return $subject; } $result = substr( $subject, 0, $location['start'] ) . substr( $subject, $location['start'] + $location['length'] ); // A block appended to an existing file is preceded by a blank line. if ( '' !== $result && "\n\n" === substr( $result, -2 ) ) { $result = substr( $result, 0, -1 ); } return $result; } /** * Whether two strings differ only in line endings and trailing newlines. * * @param string $a First string. * @param string $b Second string. * @return bool True when the difference is whitespace only. */ public static function is_whitespace_only_difference( string $a, string $b ): bool { $normalize = static function ( string $value ): string { return rtrim( str_replace( array( "\r\n", "\r" ), "\n", $value ), "\n" ); }; return $normalize( $a ) === $normalize( $b ); } }