lib/php/libsdk/SDK/FileOps.php (170 lines of code) (raw):
<?php
namespace SDK;
trait FileOps
{
protected function md(string $name = "", bool $tmp = false) : string
{/*{{{*/
$ret = $name;
if (!$name) {
if ($tmp) {
$pre = Config::getTmpDir();
$ret = $pre . DIRECTORY_SEPARATOR . md5(uniqid());
} else {
throw new Exception("Dir name is empty");
}
}
if (!is_dir($ret)) {
if (!mkdir($ret, 0755, true)) {
throw new Exception("Unable to create '$ret'");
}
}
return $ret;
}/*}}}*/
/* TODO is link and more checks. */
protected function rm(string $path) : bool
{/*{{{*/
if (!file_exists($path)) {
return false;
} else if (is_file($path)) {
return unlink($path);
}
$ret = true;
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator(
$path,
\FilesystemIterator::SKIP_DOTS
),
\RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($iterator as $item) {
if ($item->isDir()) {
$ret = $ret && rmdir($item->getPathname());
} else {
$ret = $ret && unlink($item->getPathname());
}
}
return $ret && rmdir($path);
}/*}}}*/
/* TODO islink and more checks */
protected function cp_or_mv(string $src, string $dst, callable $cb) : bool
{/*{{{*/
if (!file_exists($src)) {
return false;
} else if (is_file($src)) {
return call_user_func($cb, $src, $dst);
}
if (!file_exists($dst)) {
$this->md($dst);
}
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator(
$src,
\FilesystemIterator::SKIP_DOTS
),
\RecursiveIteratorIterator::CHILD_FIRST
);
$cut_len = strlen($src)+1;
foreach ($iterator as $item) {
$src_path = $item->getPathname();
$sub = substr($src_path, $cut_len);
$dst_path = $dst . DIRECTORY_SEPARATOR . $sub;
$dst_parent = dirname($dst_path);
if (!is_dir($dst_parent)) {
if (!$this->md($dst_parent)) {
throw new Exception("Unable to create '$dst_parent'");
}
}
if ($item->isFile()) {
if (!call_user_func($cb, $src_path, $dst_path)) {
throw new Exception("Unable to $cb '$src_path' to '$dst_path'");
}
}
}
return true;
}/*}}}*/
protected function cp(string $src, string $dst) : bool
{/*{{{*/
return $this->cp_or_mv($src, $dst, "copy");
}/*}}}*/
protected function mv(string $src, string $dst) : bool
{/*{{{*/
$ret = $this->cp_or_mv($src, $dst, "rename");
$ret = $ret && $this->rm($src);
return $ret;
}/*}}}*/
protected function download(string $url, string $dest_fn = NULL) : ?string
{/*{{{*/
$fd = NULL;
$retry = 0;
retry:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if ($dest_fn) {
$fd = fopen($dest_fn, "w+");
curl_setopt($ch, CURLOPT_FILE, $fd);
} else {
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
}
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERAGENT, Config::getSdkUserAgentName());
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
// workaround for <https://github.com/microsoft/php-sdk-binary-tools/issues/69>
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
$ret = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (false === $ret || 200 !== $code) {
$err = curl_error($ch);
curl_close($ch);
if ($dest_fn) {
fclose($fd);
}
if ($retry++ < 3) {
goto retry;
}
throw new Exception($err);
}
curl_close($ch);
if ($dest_fn) {
fclose($fd);
return NULL;
}
return $ret;
}/*}}}*/
/* TODO More detailed zip errors. */
protected function unzip(string $zip_fn, string $dest_fn, string $dest_dn = NULL) : void
{/*{{{*/
$zip = new \ZipArchive;
$res = $zip->open($zip_fn);
if (true !== $res) {
throw new Exception("Failed to open '$zip_fn'.");
}
$res = $zip->extractTo($dest_fn);
if (true !== $res) {
$zip->close();
throw new Exception("Failed to unzip '$zip_fn'.");
}
/* Not robust, useful for zips containing one dir sibling only in the root. */
if ($dest_dn) {
$stat = $zip->statIndex(0);
if (false === $stat) {
$zip->close();
throw new Exception("Failed to stat first index in '$zip_fn'.");
}
$zip->close();
/* Index of zero might be not the zipped folder, unusual but true. */
/*$name = $stat["name"];
if ("/" != substr($name, -1)) {
throw new Exception("'$name' is not a directory.");
}
$name = substr($name, 0, -1);*/
$name = rtrim($stat["name"], "/");
while (strstr($name, '/') !== false) {
$name = dirname($name);
}
$old_dir = $dest_fn . DIRECTORY_SEPARATOR . $name;
$new_dir = $dest_fn . DIRECTORY_SEPARATOR . $dest_dn;
if (file_exists($new_dir)) {
if (!$this->rm($new_dir)) {
throw new Exception("Failed to remove '$new_dir'.");
}
}
/* if (!$this->mv($old_dir, $new_dir)) { */
if (!rename($old_dir, $new_dir)) {
throw new Exception("Failed to rename '$old_dir' to '$new_dir'.");
}
} else {
$zip->close();
}
}/*}}}*/
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/