Skip to content

Instantly share code, notes, and snippets.

@aziraphale
Created January 11, 2016 16:13
Show Gist options
  • Save aziraphale/f6792ab68c84746b5ad4 to your computer and use it in GitHub Desktop.
Save aziraphale/f6792ab68c84746b5ad4 to your computer and use it in GitHub Desktop.
PHP script to convert .gz-compressed files to .bzip2 utilising the system's existing `gunzip` and `bzip2` commands
<?php
/**
* Fixes PHP's $argv array (or, rather, a list of filenames that is assumed to
* come from $argv) to expand glob strings on Windows, where the cmd.exe shell
* doesn't expand globs before passing arguments to called commands/programs.
*
* @link https://gist.github.com/aziraphale/edf8a1b1ad049f4e08ee
* @param array $argv
* @return array
*/
function windowsFixGlobArgv(array $argv)
{
// Intentionally avoid overwriting the passed array just in case we want
// to leave it untouched for other purposes
$out = [];
foreach ($argv as $v) {
if (($v[0] !== "'" && substr($v, -1) !== "'") && strlen($v) !== strcspn($v, '*?{}[]')) {
// String contains glob-style metacharacters and isn't single-quoted
$matches = glob($v, GLOB_NOSORT | GLOB_NOCHECK | GLOB_BRACE);
if ($matches && is_array($matches)) {
foreach ($matches as $match) {
$out[] = $match;
}
continue;
}
}
$out[] = $v;
}
return $out;
}
$files = array_slice($argv, 1);
if (stripos(PHP_OS, 'WIN') !== false) {
$files = windowsFixGlobArgv($files);
}
// @todo Ensure existence of `gunzip` and `bzip2` commands
// @todo Option for deleting gzipped files
// @todo Dry-run option (implies verbose on)
// @todo Verbose option
// ## DEFAULT OPTIONS ##
$deleteInputs = false;
$dryRun = false;
$verbose = false;
$continueOnErrors = false;
$continueOnInitialErrors = false;
$continueOnRuntimeErrors = false;
// ## CHANGE OPTIONS HERE FOR DEV ##
//$dryRun = true;
$verbose = true;
//$deleteInputs = true;
$outputNames = [];
foreach ($files as $f) {
try {
if (!file_exists($f)) {
throw new \RuntimeException("File `$f` does not exist.");
}
if (!is_file($f)) {
throw new \RuntimeException("File `$f` is not a 'file'.");
}
if (!is_readable($f)) {
throw new \RuntimeException("File `$f` is not readable.");
}
if (!preg_match('/\.(gz|tgz)$/iS', $f)) {
// @todo Better test here...
throw new \RuntimeException("File `$f` is not a gzipped file!");
}
$outName = $f;
$outName = preg_replace('/\.gz$/iS', '.bz2', $outName);
$outName = preg_replace('/\.tgz$/iS', '.tar.bz2', $outName);
if (file_exists($outName)) {
throw new \RuntimeException("Output file `$outName` already exists!");
}
$outputNames[$f] = $outName;
} catch (\Exception $ex) {
if ($continueOnErrors || $continueOnInitialErrors) {
echo "ERROR: {$ex->getMessage()}\r\n";
} else {
throw $ex;
}
}
}
foreach ($files as $f) {
try {
$in = $f;
$out = $outputNames[$f];
$cmd = sprintf(
'gunzip -c %s | bzip2 > %s',
escapeshellarg($in),
escapeshellarg($out)
);
if ($verbose) {
if ($dryRun) {
echo "Executing [Dry Run]: $cmd ... ";
} else {
echo "Executing: $cmd ... ";
}
}
if (!$dryRun) {
passthru($cmd, $cmdResult);
$cmdResult = 0;
if ($cmdResult === 0) {
if ($verbose) {
echo "Complete!\r\n";
}
if ($deleteInputs) {
if (unlink($in)) {
if ($verbose) {
echo "Deleted `$in`.\r\n";
}
} else {
throw new \RuntimeException("Failed to delete input file `$in`!");
}
}
} else {
echo "\r\n";
throw new \RuntimeException("Recompression failed for file `$in` => `$out`.");
}
}
} catch (\Exception $ex) {
if ($continueOnErrors || $continueOnRuntimeErrors) {
echo "ERROR: {$ex->getMessage()}\r\n";
} else {
throw $ex;
}
}
}
if ($verbose) {
echo "\r\nAll finished!\r\n";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment