如何使用纯 PHP 在不使用
exec('tar')
或任何其他命令的情况下解压 php 中的文件?
我的问题如下;我有一个 26mb tar.gz 文件,需要将其上传到我的服务器上并解压。我尝试过使用net2ftp来解压,但它不支持tar.gz上传后解压。
我正在使用免费的网络主机,因此他们不允许任何
exec()
命令,并且不允许访问提示。那么我该如何解压这个呢?
PHP 有内置命令吗?
从 PHP 5.3.0 开始,您不需要使用
Archive_Tar
。
有新的类可以处理 tar 存档:PharData 类。
PharData::extractTo()
,其工作方式类似于ZipArchive::extractTo()
):
try {
$phar = new PharData('myphar.tar');
$phar->extractTo('/full/path'); // extract all files
} catch (Exception $e) {
// handle errors
}
PharData::decompress()
):
// decompress from gz
$p = new PharData('/path/to/my.tar.gz');
$p->decompress(); // creates /path/to/my.tar
// unarchive from the tar
$phar = new PharData('/path/to/my.tar');
$phar->extractTo('/full/path');
我写了一个PHP函数,可以在没有Phar的情况下使用。 它还适用于长文件名,并使用大型 TAR 存档进行了测试。与 PHP 5 至 8 兼容。
用途:
<?php
$ret = tar_extract ("filename.tar", "./path-to-extract/");
if (empty ($ret["errText"])) {
print ($ret["fileCnt"]." files extracted.");
print ($ret["log"]);
}
else {
print ("Error: ".$ret["errText"]);
print ($ret["log"]);
}
?>
TAR 存档功能:
<?php
function tar_truncate_name (&$str) {
for ($i=0;$i<strlen ($str);$i++) {
if (0==ord (substr ($str, $i, 1)))
break;
}
$str = substr ($str, 0, $i);
}
function tar_checksum (&$str, $size) {
$checksum = 0;
for ($i=0;$i<$size;$i++) {
$checksum += ord (substr ($str, $i, 1));
}
return $checksum;
}
function tar_read_header ($fh) {
$header = array (
"name" => 100,
"mode" => 8,
"uid" => 8,
"gid" => 8,
"size" => 12,
"mtime" => 12,
"chksum" => 8,
"linkflag"=> 1,
"linkname"=> 100,
"magic" => 8,
"uname" => 32,
"gname" => 32,
"devmajor"=> 8,
"devminor"=> 8,
"rest" => 167
);
$dataPos = ftell ($fh)+512;
$stat = fstat($fh);
$filesize = $stat['size'];
if ($dataPos>$filesize) {
return -1;
}
$checksum = 0;
foreach ($header as $key => $len) {
$header[$key] = fread ($fh, $len);
$read = strlen ($header[$key]);
if ($read<$len)
return -1;
if ($key=="chksum") {
$empty = " ";
$checksum+=tar_checksum ($empty, 8);
}
else {
$checksum+=tar_checksum ($header[$key], $len);
}
}
tar_truncate_name ($header["chksum"]);
if (empty ($header["chksum"])) {
return false; // Last TAR header
}
// Check checksum
if ($header["chksum"]!=sprintf ("%06o", $checksum)) {
print_r ($header);
return -1;
}
// Convert form octal to decimal
if (sscanf ($header["size"], "%o", $header["size"])!=1)
return false;
if (sscanf ($header["mtime"], "%o", $header["mtime"])!=1)
return false;
// Truncate names
tar_truncate_name ($header["name"]);
tar_truncate_name ($header["linkname"]);
tar_truncate_name ($header["uname"]);
tar_truncate_name ($header["gname"]);
fseek ($fh, $dataPos);
if ($header["linkflag"]=="L" && $header["name"]=="././@LongLink") {
// Read long filename
$longFilename = fread ($fh, $header["size"]);
if (strlen ($longFilename)!=$header["size"])
return -1;
// Skip 512 Byte block
if ($header["size"]<512)
$size=512-$header["size"];
else
$size=(512-($header["size"] % 512));
fseek ($fh, ftell ($fh)+$size);
// Now comes the real block
$header = tar_read_header ($fh);
if (!is_array ($header)) {
return -1;
}
else {
$header["name"]=trim ($longFilename);
}
}
// Remove relative paths for security
$header["name"] = str_replace (["../", "..\\"], ["./", "./"], $header["name"]);
return $header;
}
function tar_extract ($tarFilename, $dstPath=".") {
$ret = array (
"fileCnt" => 0,
"dirCnt" => 0,
"size" => 0,
"log" => "",
"errText" => ""
);
$fh = fopen ($tarFilename, "r");
if (!$fh) {
$ret["errText"] = "Cannot open TAR file: ".$tarFilename;
$ret["log"].=$ret["errText"]."\r\n";
return $ret;
}
while (!feof ($fh)) {
$header = tar_read_header ($fh);
if (!is_array ($header)) {
if ($header==-1) {
$ret["errText"] = "TAR header corrupt.";
$ret["log"].=$ret["errText"]."\r\n";
}
break;
}
else
if ($header["linkflag"]==0) {
$ret["log"].=$header["name"].", ".$header["size"]."\r\n";
// Read file
$dstFilename = $dstPath."/".$header["name"];
$fh2 = fopen ($dstFilename, "w+");
if (!$fh2) {
$ret["errText"] = "Cannot create file: ".$dstFilename;
$ret["log"].=$ret["errText"]."\r\n";
break;
}
else {
$size = $header["size"];
$buf = "";
while ($size>0) {
$bufSize = 0xFFFF;
if ($size<$bufSize)
$bufSize=$size;
$buf = fread ($fh, $bufSize);
$read = strlen ($buf);
if ($read<=0)
break;
fwrite ($fh2, $buf);
$size-=$read;
}
fclose ($fh2);
// Set file time
touch ($dstFilename, $header["mtime"], $header["mtime"]);
if ($size>0) {
$ret["errText"] = "Filesize incorrect: ".$dstFilename;
$ret["log"].=ret["errText"]."\r\n";
break;
}
}
// Skip 512 Byte block
if (($header["size"]%512)!=0) {
if ($header["size"]<512)
$rest = 512-$header["size"];
else
$rest = 512-($header["size"] % 512);
fseek ($fh, ftell ($fh)+$rest);
}
$ret["fileCnt"]++;
$ret["size"]+=$header["size"];
}
else
if ($header["linkflag"]==5) {
if (!is_dir ($dstPath."/".$header["name"])) {
if (!mkdir ($dstPath."/".$header["name"])) {
$ret["errText"] = "Cannot create directory: ".$dstPath."/".$header["name"];
$ret["log"].=$ret["errText"]."\r\n";
break;
}
}
$ret["dirCnt"]++;
// Set directory time
touch ($dstPath."/".$header["name"], $header["mtime"], $header["mtime"]);
}
else {
// Unknown linkflag
// Ignore header but skip size
if ($header["size"]>0) {
$size = $header["size"];
// Skip 512 Byte block
if ($header["size"]<512)
$size=512;
else
$size+=(512-($header["size"] % 512));
fseek ($fh, ftell ($fh)+$size);
}
}
}
fclose ($fh);
return $ret;
}
?>