One normalized statement (with `;`) per yield. * @throws RuntimeException When the file cannot be opened for reading. */ public static function stream( string $path ): \Generator { $handle = fopen( $path, 'rb' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- WP_Filesystem has no streaming read; the dump is read line by line to bound memory. if ( false === $handle ) { throw new RuntimeException( __( 'Could not read the uploaded file.', 'shiftora' ) ); } $current = ''; $in_string = false; $string_char = ''; $in_block_comment = false; try { while ( false !== ( $line = fgets( $handle ) ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fgets -- WP_Filesystem has no streaming read; fgets reads one line at a time to bound memory. $line = str_replace( [ "\r\n", "\r" ], "\n", $line ); $length = strlen( $line ); for ( $i = 0; $i < $length; $i++ ) { $char = $line[ $i ]; if ( $in_block_comment ) { if ( '*' === $char && $i + 1 < $length && '/' === $line[ $i + 1 ] ) { $in_block_comment = false; $i++; } continue; } if ( $in_string ) { $current .= $char; if ( '\\' === $char && $i + 1 < $length ) { // Consume the escaped character so it cannot end the string. $current .= $line[ ++$i ]; } elseif ( $char === $string_char ) { $in_string = false; } continue; } // Line comments run to end of line. if ( '-' === $char && $i + 1 < $length && '-' === $line[ $i + 1 ] ) { break; } if ( '#' === $char ) { break; } if ( '/' === $char && $i + 1 < $length && '*' === $line[ $i + 1 ] ) { // An executable comment (`/*!...*/`) is real SQL (mysqldump uses them for // partitions and session setup). Keep it verbatim; the server gates by version. if ( $i + 2 < $length && '!' === $line[ $i + 2 ] ) { $current .= '/*!'; $i += 2; continue; } $in_block_comment = true; $i++; continue; } if ( '"' === $char || "'" === $char || '`' === $char ) { $in_string = true; $string_char = $char; $current .= $char; continue; } if ( ';' === $char ) { $statement = trim( preg_replace( '/^\xEF\xBB\xBF/', '', $current ) ?? $current ); if ( '' !== $statement ) { yield $statement . ';'; } $current = ''; continue; } $current .= $char; } } // A final statement may have no trailing semicolon. $statement = trim( preg_replace( '/^\xEF\xBB\xBF/', '', $current ) ?? $current ); if ( '' !== $statement ) { yield $statement; } } finally { fclose( $handle ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Closes the dump stream opened above; WP_Filesystem has no streaming read. } } // phpcs:enable WordPress.Security.EscapeOutput.ExceptionNotEscaped }