%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/bitrix/www/bitrix/modules/clouds/classes/general/
Upload File :
Create Path :
Current File : /home/bitrix/www/bitrix/modules/clouds/classes/general/storage_service_openstack.php

<?
IncludeModuleLangFile(__FILE__);

class CCloudStorageService_OpenStackStorage extends CCloudStorageService
{
	protected $status = 0;
	protected $errno = 0;
	protected $errstr = '';
	protected $result = '';
	protected $verb = '';
	protected $url = '';

	function GetLastRequestStatus()
	{
		return $this->status;
	}

	function GetObject()
	{
		return new CCloudStorageService_OpenStackStorage();
	}

	function GetID()
	{
		return "openstack_storage";
	}

	function GetName()
	{
		return "OpenStack Object Storage";
	}

	function GetLocationList()
	{
		return array(
			"" => "N/A",
		);
	}

	function GetSettingsHTML($arBucket, $bServiceSet, $cur_SERVICE_ID, $bVarsFromForm)
	{
		if($bVarsFromForm)
			$arSettings = $_POST["SETTINGS"][$this->GetID()];
		else
			$arSettings = unserialize($arBucket["SETTINGS"]);

		if(!is_array($arSettings))
		{
			$arSettings = array(
				"HOST" => "",
				"USER" => "",
				"KEY" => "",
				"FORCE_HTTP" => "N",
			);
		}

		$htmlID = htmlspecialcharsbx($this->GetID());
		$show = (($cur_SERVICE_ID == $this->GetID()) || !$bServiceSet)? '': 'none';

		$result = '
		<tr id="SETTINGS_2_'.$htmlID.'" style="display:'.$show.'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_OPENSTACK_EDIT_HOST").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][HOST]" id="'.$htmlID.'HOST" value="'.htmlspecialcharsbx($arSettings['HOST']).'"><input type="text" size="55" name="'.$htmlID.'INP_HOST" id="'.$htmlID.'INP_HOST" value="'.htmlspecialcharsbx($arSettings['HOST']).'" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'HOST\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_0_'.$htmlID.'" style="display:'.$show.'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_OPENSTACK_EDIT_USER").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][USER]" id="'.$htmlID.'USER" value="'.htmlspecialcharsbx($arSettings['USER']).'"><input type="text" size="55" name="'.$htmlID.'INP_" id="'.$htmlID.'INP_USER" value="'.htmlspecialcharsbx($arSettings['USER']).'" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'USER\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_1_'.$htmlID.'" style="display:'.$show.'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_OPENSTACK_EDIT_KEY").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][KEY]" id="'.$htmlID.'KEY" value="'.htmlspecialcharsbx($arSettings['KEY']).'"><input type="text" size="55" name="'.$htmlID.'INP_KEY" id="'.$htmlID.'INP_KEY" value="'.htmlspecialcharsbx($arSettings['KEY']).'" autocomplete="off" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'KEY\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_3_'.$htmlID.'" style="display:'.$show.'" class="settings-tr">
			<td>'.GetMessage("CLO_STORAGE_OPENSTACK_FORCE_HTTP").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][FORCE_HTTP]" id="'.$htmlID.'KEY" value="N"><input type="checkbox" name="SETTINGS['.$htmlID.'][FORCE_HTTP]" id="'.$htmlID.'FORCE_HTTP" value="Y" '.($arSettings['FORCE_HTTP'] == 'Y'? 'checked="checked"': '').'></td>
		</tr>
		';
		return $result;
	}

	function CheckSettings($arBucket, &$arSettings)
	{
		global $APPLICATION;
		$aMsg = array();

		$result = array(
			"HOST" => is_array($arSettings)? trim($arSettings["HOST"]): '',
			"USER" => is_array($arSettings)? trim($arSettings["USER"]): '',
			"KEY" => is_array($arSettings)? trim($arSettings["KEY"]): '',
			"FORCE_HTTP" => is_array($arSettings) && $arSettings["FORCE_HTTP"] == "Y"? "Y": "N",
		);

		if($arBucket["READ_ONLY"] !== "Y" && !strlen($result["HOST"]))
			$aMsg[] = array("id" => $this->GetID()."INP_HOST", "text" => GetMessage("CLO_STORAGE_OPENSTACK_EMPTY_HOST"));

		if($arBucket["READ_ONLY"] !== "Y" && !strlen($result["USER"]))
			$aMsg[] = array("id" => $this->GetID()."INP_USER", "text" => GetMessage("CLO_STORAGE_OPENSTACK_EMPTY_USER"));

		if($arBucket["READ_ONLY"] !== "Y" && !strlen($result["KEY"]))
			$aMsg[] = array("id" => $this->GetID()."INP_KEY", "text" => GetMessage("CLO_STORAGE_OPENSTACK_EMPTY_KEY"));


		if(empty($aMsg))
		{
			if(!$this->_GetToken($result["HOST"], $result["USER"], $result["KEY"]))
				$aMsg[] = array("text" => GetMessage("CLO_STORAGE_OPENSTACK_ERROR_GET_TOKEN"));
		}

		if(!empty($aMsg))
		{
			$e = new CAdminException($aMsg);
			$APPLICATION->ThrowException($e);
			return false;
		}
		else
		{
			$arSettings = $result;
		}

		return true;
	}

	function _GetToken($host, $user, $key)
	{
		global $APPLICATION;
		static $results = array();
		$cache_id = "v0|".$host."|".$user."|".$key;

		if(array_key_exists($cache_id, $results))
		{
			$result = $results[$cache_id];
		}
		else
		{
			$result = false;
			$obCache = new CPHPCache;

			if($obCache->InitCache(600, $cache_id, "/")) /*TODO make setting*/
			{
				$result = $obCache->GetVars();
			}
			else
			{
				$obRequest = new CHTTP;
				$obRequest->additional_headers["X-Auth-User"] = $user;
				$obRequest->additional_headers["X-Auth-Key"] = $key;
				$obRequest->Query("GET", $host, 80, "/v1.0");
				if($obRequest->status == 412)
				{
					$APPLICATION->ResetException();
					$obRequest = new CHTTP;
					$obRequest->additional_headers["X-Auth-User"] = $user;
					$obRequest->additional_headers["X-Auth-Key"] = $key;
					$obRequest->Query("GET", $host, 80, "/auth/v1.0");
				}

				if($obRequest->status == 204 || $obRequest->status == 200)
				{
					$arStorage = array();
					if(preg_match("#^http://(.*?)(|:\d+)(/.*)\$#", $obRequest->headers["X-Storage-Url"], $arStorage))
					{
						$result = $obRequest->headers;
						$result["X-Storage-NoProtoUrl"] = $arStorage[1].($arStorage[2] == ':80'? '': $arStorage[2]).$arStorage[3];
						$result["X-Storage-Host"] = $arStorage[1];
						$result["X-Storage-Port"] = $arStorage[2]? substr($arStorage[2], 1): 80;
						$result["X-Storage-Urn"] = $arStorage[3];
						$result["X-Storage-Proto"] = "";
					}
				}
			}

			if(is_array($result))
			{
				if($obCache->StartDataCache())
					$obCache->EndDataCache($result);
			}

			$results[$cache_id] = $result;
		}

		return $result;
	}

	function SendRequest($settings, $verb, $bucket, $file_name='', $params='', $content=false, $additional_headers=array())
	{
		$arToken = $this->_GetToken($settings["HOST"], $settings["USER"], $settings["KEY"]);
		if(!$arToken)
			return false;

		$this->status = 0;
		$obRequest = new CHTTP;

		$RequestURI = $file_name;

		$ContentType = "N";
		$obRequest->additional_headers["X-Auth-Token"] = $arToken["X-Auth-Token"];
		foreach($additional_headers as $key => $value)
		{
			if($key == "Content-Type")
				$ContentType = $value;
			else
				$obRequest->additional_headers[$key] = $value;
		}

		@$obRequest->Query(
			$this->verb = $verb,
			$arToken["X-Storage-Host"],
			$arToken["X-Storage-Port"],
			$this->url = $arToken["X-Storage-Urn"]."/".$bucket.$RequestURI.$params,
			$content,
			$arToken["X-Storage-Proto"],
			$ContentType
		);
		$this->status = $obRequest->status;
		$this->errno = $obRequest->errno;
		$this->errstr = $obRequest->errstr;
		$this->result = $obRequest->result;

		return $obRequest;
	}

	function CreateBucket($arBucket)
	{
		global $APPLICATION;

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"PUT",
			$arBucket["BUCKET"],
			'', //filename
			'', //params
			false, //content
			array(
				"X-Container-Read" => ".r:*",
				"X-Container-Meta-Web-Listings" => "false",
				"X-Container-Meta-Type" => "public",
			)
		);

		return ($this->status == 201)/*Created*/ || ($this->status == 202) /*Accepted*/;
	}

	function DeleteBucket($arBucket)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			//Do not delete bucket if there is some files left
			if(!$this->IsEmptyBucket($arBucket))
				return false;

			//Do not delete bucket if there is some files left in other prefixes
			$arAllBucket = $arBucket;
			$arBucket["PREFIX"] = "";
			if(!$this->IsEmptyBucket($arAllBucket))
				return true;
		}

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"DELETE",
			$arBucket["BUCKET"]
		);

		if(
			$this->status == 204/*No Content*/
			|| $this->status == 404/*Not Found*/
		)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	function IsEmptyBucket($arBucket)
	{
		global $APPLICATION;

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"GET",
			$arBucket["BUCKET"],
			'',
			"?limit=1&format=xml".($arBucket["PREFIX"]? '&prefix='.$arBucket["PREFIX"]: '')
		);

		$arXML = false;
		if(is_object($obRequest) && $obRequest->result)
		{
			$obXML = new CDataXML;
			$text = preg_replace("/<"."\\?XML.*?\\?".">/i", "", $obRequest->result);
			if($obXML->LoadString($text))
			{
				$arXML = $obXML->GetArray();
			}
		}

		if($this->status == 404)
		{
			return true;
		}
		elseif(is_array($arXML))
		{
			return
				!isset($arXML["container"])
				|| !is_array($arXML["container"])
				|| !isset($arXML["container"]["#"])
				|| !is_array($arXML["container"]["#"])
				|| !isset($arXML["container"]["#"]["object"])
				|| !is_array($arXML["container"]["#"]["object"]);
		}
		else
		{
			return false;
		}
	}

	function GetFileSRC($arBucket, $arFile)
	{
		global $APPLICATION;
		
		if ($arBucket["SETTINGS"]["FORCE_HTTP"] === "Y")
			$proto = "http";
		else
			$proto = ($APPLICATION->IsHTTPS()? "https": "http");

		if($arBucket["CNAME"])
		{
			$host = $proto."://".$arBucket["CNAME"];
		}
		else
		{
			$arToken = $this->_GetToken(
				$arBucket["SETTINGS"]["HOST"],
				$arBucket["SETTINGS"]["USER"],
				$arBucket["SETTINGS"]["KEY"]
			);

			if(is_array($arToken))
			{
				if ($arToken["X-Storage-NoProtoUrl"])
					$host = $proto."://".$arToken["X-Storage-NoProtoUrl"]."/".$arBucket["BUCKET"];
				else
					$host = $arToken["X-Storage-Url"]."/".$arBucket["BUCKET"];
			}
			else
			{
				return "/404.php";
			}
		}

		if(is_array($arFile))
			$URI = ltrim($arFile["SUBDIR"]."/".$arFile["FILE_NAME"], "/");
		else
			$URI = ltrim($arFile, "/");

		if($arBucket["PREFIX"])
		{
			if(substr($URI, 0, strlen($arBucket["PREFIX"])+1) !== $arBucket["PREFIX"]."/")
				$URI = $arBucket["PREFIX"]."/".$URI;
		}

		return $host."/".CCloudUtil::URLEncode($URI, "UTF-8");
	}

	function FileExists($arBucket, $filePath)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"HEAD",
			$arBucket["BUCKET"],
			$filePath
		);

		return ($this->status == 200 || $this->status == 206);
	}

	function FileCopy($arBucket, $arFile, $filePath)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"PUT",
			$arBucket["BUCKET"],
			CCloudUtil::URLEncode($filePath, "UTF-8"),
			'',
			false,
			array(
				"X-Copy-From" => CCloudUtil::URLEncode("/".$arBucket["BUCKET"]."/".($arBucket["PREFIX"]? $arBucket["PREFIX"]."/": "").($arFile["SUBDIR"]? $arFile["SUBDIR"]."/": "").$arFile["FILE_NAME"], "UTF-8"),
			)
		);

		if($this->status == 200 || $this->status == 201)
			return $this->GetFileSRC($arBucket, $filePath);
		else
			return false;
	}

	function DownloadToFile($arBucket, $arFile, $filePath)
	{
		$io = CBXVirtualIo::GetInstance();
		$obRequest = new CHTTP;
		$obRequest->follow_redirect = true;
		return $obRequest->Download($this->GetFileSRC($arBucket, $arFile), $io->GetPhysicalName($filePath));
	}

	function DeleteFile($arBucket, $filePath)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");
		$filePath = str_replace('+', '%20', $filePath);

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"DELETE",
			$arBucket["BUCKET"],
			$filePath
		);

		//Try to fix space in the path
		if ($this->status == 404 && strpos($filePath, '+') !== false)
		{
			$filePath = str_replace('+', '%20', $filePath);
			$obRequest = $this->SendRequest(
				$arBucket["SETTINGS"],
				"DELETE",
				$arBucket["BUCKET"],
				$filePath
			);
		}

		if($this->status == 204 || $this->status == 404)
		{
			$APPLICATION->ResetException();
			return true;
		}
		else
		{
			$APPLICATION->ResetException();
			return false;
		}
	}

	function SaveFile($arBucket, $filePath, $arFile)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		if (array_key_exists("content", $arFile))
		{
			$obRequest = $this->SendRequest(
				$arBucket["SETTINGS"],
				"PUT",
				$arBucket["BUCKET"],
				$filePath,
				"",
				$arFile["content"],
				array(
					"Content-Type" => $arFile["type"],
					"Content-Length" => CUtil::BinStrlen($arFile["content"]),
				)
			);
		}
		else
		{
			$obRequest = $this->SendRequest(
				$arBucket["SETTINGS"],
				"PUT",
				$arBucket["BUCKET"],
				$filePath,
				"",
				fopen($arFile["tmp_name"], "rb"),
				array(
					"Content-Type" => $arFile["type"],
					"Content-Length" => filesize($arFile["tmp_name"]),
				)
			);
		}

		if($obRequest->status == 201)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	function ListFiles($arBucket, $filePath, $bRecursive = false)
	{
		global $APPLICATION;

		$result = array(
			"dir" => array(),
			"file" => array(),
			"file_size" => array(),
		);

		$filePath = trim($filePath, '/');
		if(strlen($filePath))
			$filePath .= '/';

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = $arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = $APPLICATION->ConvertCharset($filePath, LANG_CHARSET, "UTF-8");

		$marker = '';
		$new_marker = false;
		while(true)
		{
			$obRequest = $this->SendRequest(
				$arBucket["SETTINGS"],
				"GET",
				$arBucket["BUCKET"],
				'/',
				$s='?format=xml&'.($bRecursive? '': '&delimiter=/').'&prefix='.urlencode($filePath).'&marker='.urlencode($marker)
			);
			$bFound = false;
			if(is_object($obRequest) && $obRequest->result && $this->status == 200)
			{
				$obXML = new CDataXML;
				$text = preg_replace("/<"."\\?XML.*?\\?".">/i", "", $obRequest->result);
				if($obXML->LoadString($text))
				{
					$arXML = $obXML->GetArray();
					if(
						isset($arXML["container"])
						&& is_array($arXML["container"])
						&& isset($arXML["container"]["#"])
						&& is_array($arXML["container"]["#"])
						&& !empty($arXML["container"]["#"])
					)
					{
						if(
							isset($arXML["container"]["#"]["object"])
							&& is_array($arXML["container"]["#"]["object"])
							&& !empty($arXML["container"]["#"]["object"])
						)
						{
							$bFound = true;
							foreach($arXML["container"]["#"]["object"] as $a)
							{
								$new_marker = $a["#"]["name"][0]["#"];
								if($a["#"]["content_type"][0]["#"] === "application/directory")
								{
									$dir_name = trim(substr($a["#"]["name"][0]["#"], strlen($filePath)), "/");
									$result["dir"][$APPLICATION->ConvertCharset(urldecode($dir_name), "UTF-8", LANG_CHARSET)] = true;
								}
								else
								{
									$file_name = substr($a["#"]["name"][0]["#"], strlen($filePath));
									$file_name = $APPLICATION->ConvertCharset(urldecode($file_name), "UTF-8", LANG_CHARSET);
									if (!in_array($file_name, $result["file"]))
									{
										$result["file"][] = $file_name;
										$result["file_size"][] = $a["#"]["bytes"][0]["#"];
									}
								}
							}
						}

						if(
							isset($arXML["container"]["#"]["subdir"])
							&& is_array($arXML["container"]["#"]["subdir"])
							&& !empty($arXML["container"]["#"]["subdir"])
						)
						{
							$bFound = true;
							foreach($arXML["container"]["#"]["subdir"] as $a)
							{
								$new_marker = $a["@"]["name"];
								$dir_name = trim(substr($a["@"]["name"], strlen($filePath)), "/");
								$result["dir"][$APPLICATION->ConvertCharset(urldecode($dir_name), "UTF-8", LANG_CHARSET)] = true;
							}
						}
					}
				}
			}
			else
			{
				return false;
			}

			if($new_marker === $marker)
				break;

			if(!$bFound)
				break;

			$marker = $new_marker;
		}
		$result["dir"] = array_keys($result["dir"]);
		return $result;
	}

	function InitiateMultipartUpload($arBucket, &$NS, $filePath, $fileSize, $ContentType)
	{
		$filePath = '/'.trim($filePath, '/');
		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"].$filePath;
		}

		$NS = array(
			"filePath" => $filePath,
			"fileTemp" => CCloudStorage::translit("/tmp".str_replace(' ', '_', $filePath), "/"),
			"partsCount" => 0,
			"Parts" => array(),
			"Content-Type" => $ContentType,
		);

		return true;
	}

	function GetMinUploadPartSize()
	{
		return 5*1024*1024; //5MB
	}

	function UploadPartNo($arBucket, &$NS, $data, $part_no)
	{
		$filePath = $NS["fileTemp"]."/".sprintf("%06d", $part_no + 1);
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"PUT",
			$arBucket["BUCKET"],
			$filePath,
			"",
			$data
		);

		if(is_object($obRequest) && $this->status == 201)
		{
			$NS["partsCount"]++;
			$NS["Parts"][$part_no] = $filePath;
			return true;
		}
		else
		{
			return false;
		}
	}

	function UploadPart($arBucket, &$NS, $data)
	{
		return $this->UploadPartNo($arBucket, $NS, $data, count($NS["Parts"]));
	}

	function CompleteMultipartUpload($arBucket, &$NS)
	{
		$filePath = CCloudUtil::URLEncode($NS["fileTemp"], "UTF-8");

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"PUT",
			$arBucket["BUCKET"],
			$filePath,
			"",
			false,
			array(
				"Content-Type" => $NS["Content-Type"],
				"X-Object-Manifest" => $arBucket["BUCKET"].$filePath."/",
			)
		);

		if(is_object($obRequest) && $this->status == 201)
		{
			$obRequest = $this->SendRequest(
				$arBucket["SETTINGS"],
				"PUT",
				$arBucket["BUCKET"],
				CCloudUtil::URLEncode($NS["filePath"], "UTF-8"),
				'',
				false,
				array(
					"Content-Type" => $NS["Content-Type"],
					"X-Copy-From" => "/".$arBucket["BUCKET"].$filePath,
				)
			);

			if(
				is_object($obRequest)
				&& (
					$this->status == 201
					|| $this->status == 200
				)
			)
				$result = true;
			else
				$result = false;

			$this->DeleteFile($arBucket, $NS["fileTemp"]);
			ksort($NS["Parts"]);
			foreach ($NS["Parts"] as $tmpPath)
			{
				$this->DeleteFile($arBucket, $tmpPath);
			}

			return $result;
		}
		else
		{
			//May be delete uploaded tmp file?
			return false;
		}
	}
}
?>

Zerion Mini Shell 1.0