将PHP的proc_open代码转为Python的Popen,求获取$pipeOutput的方法
Got it, let's tackle the proc_open translation to Python since you've already sorted the CRC32b part. The goal here is to replicate that PHP pipeline where you feed the hashed data into xz and capture its output—here's how to do it properly:
First, let's double-check your CRC32b implementation to make sure it's fully aligned with PHP's behavior (since this feeds into the xz step):
PHP's strrev(hash("crc32b", $data, true)) returns the little-endian binary representation of the CRC32 value. In Python, you can replicate this with zlib and struct:
import zlib import struct def php_crc32b(data: bytes) -> bytes: # Calculate CRC32 (ensure it's an unsigned 32-bit integer) crc_value = zlib.crc32(data) & 0xFFFFFFFF # Pack as little-endian 4-byte binary (matches strrev(hash(...)) in PHP) return struct.pack('<I', crc_value)
Now for the proc_open equivalent—Python's subprocess.Popen is the right tool here, as it lets you create bidirectional pipes with an external process, just like PHP's proc_open. Here's the full implementation to get your equivalent $pipeOutput:
import subprocess import shutil def get_xz_compressed_data(data: bytes) -> bytes: # Step 1: Create the hashed data exactly like PHP hashed_data = php_crc32b(data) + data # Step 2: Locate the xz binary (matches PHP's `which xz`) xz_binary = shutil.which("xz") if not xz_binary: raise RuntimeError("xz command not found in your system PATH") # Step 3: Define the xz command arguments (avoid shell=True for safety) xz_args = [ xz_binary, "--format=raw", "--lzma1=lc=3,lp=0,pb=2,dict=128KiB", "-c", # Write output to stdout "-" # Read input from stdin ] # Step 4: Launch xz process with pipes (equivalent to proc_open) try: # Start the process with stdin/stdout pipes proc = subprocess.Popen( xz_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) # Feed the hashed data to xz and capture output/errors # communicate() handles writing to stdin, reading stdout/stderr, and waiting for the process stdout, stderr = proc.communicate(input=hashed_data) # Check if xz ran successfully if proc.returncode != 0: raise RuntimeError(f"xz failed with code {proc.returncode}: {stderr.decode('utf-8')}") # stdout is your equivalent of PHP's $pipeOutput return stdout except Exception as e: raise RuntimeError(f"Error executing xz process: {str(e)}") # Example usage if __name__ == "__main__": input_data = b"your_actual_data_here" # Replace with your $data (as bytes) pipe_output = get_xz_compressed_data(input_data) # Do something with pipe_output
Key Notes About the Translation:
shutil.which("xz"): This is the safe, cross-platform replacement for PHP's`which xz`—it finds the xz executable without relying on shell parsing.subprocess.Popen+communicate(): This replaces PHP'sproc_open,fwrite, andfreadcalls. Usingcommunicate()is safer than manual pipe reading/writing because it prevents deadlocks between the parent and child processes.- Argument List: We pass the command as a list of arguments instead of a string with
shell=True—this avoids shell injection vulnerabilities and works consistently across operating systems. - Binary Data: All data handling uses
bytes(not strings) to match PHP's binary pipeline behavior. If your input is a string, make sure to encode it first (e.g.,input_data = "my string".encode("utf-8")).
内容的提问来源于stack exchange,提问作者Milano

