',
+
+ ];
+
+ } else {
+
+ /** Verifica se o usuário já se encontra cadastrado */
+ if($Users->CheckEmail($UsersValidate->getUsersId(), $UsersValidate->getClientsId(), $UsersValidate->getEmail()) > 0){
+
+ /** Informo */
+ throw new InvalidArgumentException('O e-mail informado já está sendo utilizado', 0);
+ }
+
+
+ /** Efetua um novo cadastro ou salva os novos dados */
+ if ($Users->Save($UsersValidate->getUsersId(), $UsersValidate->getClientsId(), $UsersValidate->getCompanyId(), $UsersValidate->getNameFirst(), $UsersValidate->getNameLast(), $UsersValidate->getEmail(), $UsersValidate->getBirthDate(), $UsersValidate->getGenre(), $UsersValidate->getActive(), $UsersValidate->getAdministrator(), $UsersValidate->getPassword(), $UsersValidate->getPasswordTemp(), $UsersValidate->getPasswordTempConfirm())){
+
+
+ /** Verifica se é para enviar e-mail de acesso ao usuário */
+ if($UsersValidate->getPasswordTempConfirm() == 'S'){
+
+ /** Trata a mensagem a ser enviada */
+ $body = str_replace('{[EMAIL]}', $UsersValidate->getEmail(), base64_decode($settings->app->mail->messages->new_user));
+ $body = str_replace('{[SENHA]}', $UsersValidate->getPassword(), $body);
+
+ /** Envia a mensagem */
+ $Mail->sendMail($settings->app->mail->host,# Servidor do e-mail
+ $settings->app->mail->username,# Usuário do e-mail
+ $settings->app->mail->password,# Senha do e-mail de envio
+ $settings->app->mail->port,# Porta de envio
+ $settings->app->mail->from->email,# E-mail de envio
+ $settings->app->mail->from->name,# Nome de envio
+ $UsersValidate->getEmail(),# E-mai destino
+ $settings->app->mail->from->name,# Nome destino
+ 'Dados de acesso para ambiente de impressão de boletos',# Assunto do e-mail
+ $body# Mensagem a ser enviada
+ );
+ }
+
+ /** Adição de elementos na array */
+ $message = '
'.($UsersValidate->getUsersId() > 0 ? 'Cadastro atualizado com sucesso' : 'Cadastro efetuado com sucesso').'
' . ($UsersValidate->getUsersId() > 0 ? 'Não foi possível atualizar o cadastro' : 'Não foi possível efetuar o cadastro') .'
';
+
+ /** Result **/
+ $result = [
+
+ 'cod' => 0,
+ 'title' => 'Atenção',
+ 'message' => $message,
+
+ ];
+
+ }
+
+ }
+
+ /** Envio **/
+ echo json_encode($result);
+
+ /** Paro o procedimento **/
+ exit;
+
+ /** Caso o token de acesso seja inválido, informo */
+ }else{
+
+ /** Informa que o usuário precisa efetuar autenticação junto ao sistema */
+ $authenticate = true;
+
+ /** Informo */
+ throw new InvalidArgumentException('Sua sessão expirou é necessário efetuar nova autenticação junto ao sistema', 0);
+ }
+
+} catch (Exception $exception) {
+
+ /** Controle de mensagens */
+ /*$message = 'Detalhes.: ' . 'código = ' . $exception->getCode() . ' - linha = ' . $exception->getLine() . ' - arquivo = ' . $exception->getFile() . '';
+ $message .= 'Mensagem.: ' . $exception->getMessage();*/
+
+ /** Preparo o formulario para retorno **/
+ $result = [
+
+ 'cod' => 500,
+ 'message' => '
'.$exception->getMessage().'
',
+ 'title' => 'Atenção',
+ 'type' => 'exception',
+ 'authenticate' => $authenticate
+
+ ];
+
+ /** Envio **/
+ echo json_encode($result);
+
+ /** Paro o procedimento **/
+ exit;
+
+}
diff --git a/vendor/autoload.php b/vendor/autoload.php
new file mode 100644
index 0000000..e5ee0d2
--- /dev/null
+++ b/vendor/autoload.php
@@ -0,0 +1,8 @@
+Main = new Main();
+
+ }
+
/** Método trata campo backup_id */
+ public function setBackupId(int $backupId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->backupId = isset($backupId) ? $this->Main->antiInjection($backupId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->backupId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "backup_id", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo client_id */
+ public function setClientId(int $clientId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->clientId = isset($clientId) ? $this->Main->antiInjection($clientId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->clientId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "client_id", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo file */
+ public function setFile(string $file) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->file = isset($file) ? $this->Main->antiInjection($file) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->file))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "file", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo file_date */
+ public function setFileDate(string $fileDate) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->fileDate = isset($fileDate) ? $this->Main->antiInjection($fileDate) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->fileDate))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "file_date", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo file_hour */
+ public function setFileHour(string $fileHour) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->fileHour = isset($fileHour) ? $this->Main->antiInjection($fileHour) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->fileHour))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "file_hour", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo period */
+ public function setPeriod(int $period) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->period = isset($period) ? $this->Main->antiInjection($period) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->period))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "period", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo day */
+ public function setDay(string $day) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->day = isset($day) ? $this->Main->antiInjection($day) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->day))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "day", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo size */
+ public function setSize(string $size) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->size = isset($size) ? $this->Main->antiInjection($size) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->size))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "size", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo path */
+ public function setPath(string $path) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->path = isset($path) ? $this->Main->antiInjection($path) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->path))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "path", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo date_register */
+ public function setDateRegister(string $dateRegister) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->dateRegister = isset($dateRegister) ? $this->Main->antiInjection($dateRegister) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->dateRegister))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "date_register", deve ser informado');
+
+ }
+
+ }
+
+ /** Método retorna campo backup_id */
+ public function getBackupId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->backupId;
+
+ }
+
+ /** Método retorna campo client_id */
+ public function getClientId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->clientId;
+
+ }
+
+ /** Método retorna campo file */
+ public function getFile() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->file;
+
+ }
+
+ /** Método retorna campo file_date */
+ public function getFileDate() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->fileDate;
+
+ }
+
+ /** Método retorna campo file_hour */
+ public function getFileHour() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->fileHour;
+
+ }
+
+ /** Método retorna campo period */
+ public function getPeriod() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->period;
+
+ }
+
+ /** Método retorna campo day */
+ public function getDay() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->day;
+
+ }
+
+ /** Método retorna campo size */
+ public function getSize() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->size;
+
+ }
+
+ /** Método retorna campo path */
+ public function getPath() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->path;
+
+ }
+
+ /** Método retorna campo date_register */
+ public function getDateRegister() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->dateRegister;
+
+ }
+
+ public function getErrors(): ? string
+ {
+
+ /** Verifico se deve informar os erros */
+ if (count($this->errors)) {
+
+ /** Verifica a quantidade de erros para informar a legenda */
+ $this->info = count($this->errors) > 1 ? '
Os seguintes erros foram encontrados
' : '
O seguinte erro foi encontrado
';
+
+ /** Lista os erros */
+ foreach ($this->errors as $keyError => $error) {
+
+ /** Monto a mensagem de erro */
+ $this->info .= '' . ($keyError + 1) . ' - ' . $error;
+
+ }
+
+ /** Retorno os erros encontrados */
+ return (string)$this->info;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ function __destruct(){}
+
}
\ No newline at end of file
diff --git a/vendor/controller/client/ClientValidate.class.php b/vendor/controller/client/ClientValidate.class.php
new file mode 100644
index 0000000..c40869d
--- /dev/null
+++ b/vendor/controller/client/ClientValidate.class.php
@@ -0,0 +1,318 @@
+Main = new Main();
+
+ }
+
+ /** Método trata campo client_id */
+ public function setClientId(int $clientId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->clientId = isset($clientId) ? $this->Main->antiInjection($clientId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->clientId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "client_id", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo cns */
+ public function setCns(string $cns) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->cns = isset($cns) ? $this->Main->antiInjection($cns) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->cns))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo CNS deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo name */
+ public function setName(string $name) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->name = isset($name) ? $this->Main->antiInjection($name) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->name))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "name", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo date_register */
+ public function setDateRegister(string $dateRegister) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->dateRegister = isset($dateRegister) ? $this->Main->antiInjection($dateRegister) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->dateRegister))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "date_register", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo state */
+ public function setState(string $state) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->state = isset($state) ? $this->Main->antiInjection($state) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->state))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo Estado/UF deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo city */
+ public function setCity(string $city) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->city = isset($city) ? $this->Main->antiInjection($city) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->city))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "cidade deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo responsible */
+ public function setResponsible(string $responsible) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->responsible = isset($responsible) ? $this->Main->antiInjection($responsible) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->responsible))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo responsável deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo consultant */
+ public function setConsultant(string $consultant) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->consultant = isset($consultant) ? $this->Main->antiInjection($consultant) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->consultant))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo consultor deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo type_contract */
+ public function setTypeContract(string $typeContract) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->typeContract = isset($typeContract) ? $this->Main->antiInjection($typeContract) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->typeContract))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo contrato deve ser selecionado');
+
+ }
+
+ }
+
+ /** Método retorna campo client_id */
+ public function getClientId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->clientId;
+
+ }
+
+ /** Método retorna campo cns */
+ public function getCns() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->cns;
+
+ }
+
+ /** Método retorna campo name */
+ public function getName() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->name;
+
+ }
+
+ /** Método retorna campo date_register */
+ public function getDateRegister() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->dateRegister;
+
+ }
+
+ /** Método retorna campo state */
+ public function getState() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->state;
+
+ }
+
+ /** Método retorna campo city */
+ public function getCity() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->city;
+
+ }
+
+ /** Método retorna campo responsible */
+ public function getResponsible() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->responsible;
+
+ }
+
+ /** Método retorna campo consultant */
+ public function getConsultant() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->consultant;
+
+ }
+
+ /** Método retorna campo type_contract */
+ public function getTypeContract() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->typeContract;
+
+ }
+
+ public function getErrors(): ? string
+ {
+
+ /** Verifico se deve informar os erros */
+ if (count($this->errors)) {
+
+ /** Verifica a quantidade de erros para informar a legenda */
+ $this->info = count($this->errors) > 1 ? '
Os seguintes erros foram encontrados
' : '
O seguinte erro foi encontrado
';
+
+ /** Lista os erros */
+ foreach ($this->errors as $keyError => $error) {
+
+ /** Monto a mensagem de erro */
+ $this->info .= '' . ($keyError + 1) . ' - ' . $error;
+
+ }
+
+ /** Retorno os erros encontrados */
+ return (string)$this->info;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ function __destruct(){}
+
+}
diff --git a/vendor/controller/log/LogValidate.class.php b/vendor/controller/log/LogValidate.class.php
new file mode 100644
index 0000000..3b2262b
--- /dev/null
+++ b/vendor/controller/log/LogValidate.class.php
@@ -0,0 +1,227 @@
+Main = new Main();
+
+ }
+
+ /** Método trata campo key */
+ public function setKey(string $key) : void
+ {
+
+ $this->key = !empty($key) ? $this->Main->antiInjection($key) : null;
+
+ /** Verifica se a chave foi informada */
+ if(!empty($key))
+ {
+
+ // Verifica se a senha tem pelo menos 8 caracteres
+ if (strlen($this->key) < 8) {
+
+ array_push($this->errors, 'A senha deve ter pelo menos 8 caracteres.');
+ }
+
+ // Verifica se a senha contém pelo menos uma letra maiúscula
+ if (!preg_match('/[A-Z]/', $this->key)) {
+
+ array_push($this->errors, 'A senha deve conter pelo menos uma letra maiúscula.');
+ }
+
+ // Verifica se a senha contém pelo menos uma letra minúscula
+ if (!preg_match('/[a-z]/', $this->key)) {
+
+ array_push($this->errors, 'A senha deve conter pelo menos uma letra minúscula.');
+ }
+
+ // Verifica se a senha contém pelo menos um número
+ if (!preg_match('/\d/', $this->key)) {
+
+ array_push($this->errors, 'A senha deve conter pelo menos um número.');
+ }
+
+ // Verifica se a senha contém pelo menos um caractere especial
+ if (!preg_match('/[\W_]/', $this->key)) {
+
+ array_push($this->errors, 'A senha deve conter pelo menos um caractere especial.');
+ }
+
+ } else {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'É preciso informar uma chave válida');
+ }
+ }
+
+ /** Método trata campo log_id */
+ public function setLogId(int $logId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->logId = isset($logId) ? $this->Main->antiInjection($logId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->logId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "log_id", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo client_id */
+ public function setClientId(int $clientId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->clientId = isset($clientId) ? $this->Main->antiInjection($clientId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->clientId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "client_id", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo date_post */
+ public function setDatePost(string $datePost) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->datePost = isset($datePost) ? $this->Main->antiInjection($datePost) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->datePost))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "date_post", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo file */
+ public function setFile(string $file) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->file = isset($file) ? base64_decode($this->Main->antiInjection($file)) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->file))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "file", deve ser informado');
+
+ }
+ }
+
+ /** Método retorna campo log_id */
+ public function getLogId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->logId;
+
+ }
+
+ /** Método retorna campo client_id */
+ public function getClientId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->clientId;
+
+ }
+
+ /** Método retorna campo date_post */
+ public function getDatePost() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->datePost;
+
+ }
+
+ /** Método retorna campo file */
+ public function getFile() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->file;
+
+ }
+
+ public function getErrors(): ? string
+ {
+
+ /** Verifico se deve informar os erros */
+ if (count($this->errors)) {
+
+ /** Verifica a quantidade de erros para informar a legenda */
+ $this->info = count($this->errors) > 1 ? '
Os seguintes erros foram encontrados
' : '
O seguinte erro foi encontrado
';
+
+ /** Lista os erros */
+ foreach ($this->errors as $keyError => $error) {
+
+ /** Monto a mensagem de erro */
+ $this->info .= '' . ($keyError + 1) . ' - ' . $error;
+
+ }
+
+ /** Retorno os erros encontrados */
+ return (string)$this->info;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ function __destruct(){}
+
+}
+
diff --git a/vendor/controller/main/Main.class.php b/vendor/controller/main/Main.class.php
new file mode 100644
index 0000000..64aad16
--- /dev/null
+++ b/vendor/controller/main/Main.class.php
@@ -0,0 +1,1387 @@
+config = $this->LoadConfigPublic();
+
+ /** Parametros para descriptografar dados */
+ $this->method = $this->config->{'app'}->{'security'}->{'method'};
+ $this->firstKey = $this->config->{'app'}->{'security'}->{'first_key'};
+ $this->secondKey = $this->config->{'app'}->{'security'}->{'second_key'};
+ $this->hash = $this->config->{'app'}->{'security'}->{'hash'};
+
+ /** Parametro do tempo de sessão do usuário */
+ $this->sessionTime = $this->config->{'app'}->{'session_time'};
+
+ }
+
+ /** Retorna o metodo de criptografia */
+ private function getMethod()
+ {
+
+ return $this->method;
+ }
+
+ /** Retorna a primeira chave de criptografia */
+ private function getFirstKey()
+ {
+
+ return $this->firstKey;
+ }
+
+ //** Retorna a segunda chave de criptografia */
+ private function getSecondKey()
+ {
+
+ return $this->secondKey;
+ }
+
+ /** Retorna o tempo de sessão */
+ public function getSessionTime() : int
+ {
+
+ return (int)$this->sessionTime;
+ }
+
+ /** Retorna a string descriptografada */
+ public function decryptData(string $data) : string
+ {
+
+ /** Parametro de entrada */
+ $this->data = $data;
+
+
+ /** Verifica se a string a se descriptografada foi informada */
+ if(!empty($this->data)){
+
+ return $this->securedDecrypt($this->getFirstKey(), $this->getMethod(), $this->data);
+
+ }else{
+
+ return $this->data;
+ }
+
+ }
+
+ /** Retorna a string criptografada */
+ public function encryptData(string $data) : string
+ {
+
+ /** Parametro de entrada */
+ $this->data = $data;
+
+ /** Verifica se a string a se criptografada foi informada */
+ if(!empty($this->data)){
+
+ return $this->securedEncrypt($this->getFirstKey(), $this->getSecondKey(), $this->getMethod(), $this->data);
+
+ }else{
+
+ return $this->data;
+ }
+
+ }
+
+
+ /** Verifica se o token do usuário é válido */
+ public function verifyToken() : bool
+ {
+
+ /** Verifica se o token foi inicializado e não esta vazio */
+ if( isset($_SESSION['USERSTOKEN']) && !empty($_SESSION['USERSTOKEN']) ){
+
+ /** Caso o token tenha sido inicializado e não esteja vazio, verifica-se o mesmo é válido */
+ $this->token = explode('-', $this->decryptData($_SESSION['USERSTOKEN']));
+
+ /** Verifica se o hash é válido */
+ if( ($this->token[0] === $this->hash) && ($this->token[1] === $_SESSION['USERSID']) && ($this->token[2] == session_id()) ){
+
+
+ /**Caso o usuario não esteja logado informo*/
+ if( (!isset($_SESSION['USERSID'])) || ((int)$_SESSION['USERSID'] == 0) )
+ {
+ /**Elimina as sessões atuais*/
+ session_destroy();
+
+ /**Gera um novo session_id*/
+ session_regenerate_id();
+
+ return false;
+ }
+
+ /**Caso o usuário esteja logado no sistema e o tempo de sessão tenha excedido o permitido */
+ elseif($this->checkTime($_SESSION['USERSSTARTTIME']) > $this->sessionTime)
+ {
+ /**Destruo as sessões atuais*/
+ @session_destroy();
+
+ /**Gera um novo session_id*/
+ @session_regenerate_id();
+
+ return false;
+
+ /** Caso esteja tudo certo, libera o acesso */
+ }else{
+
+ /** Renova o tempo da sessão do usuário */
+ $_SESSION['USERSSTARTTIME'] = date("Y-m-d H:i:s");
+
+ return true;
+
+ }
+
+ }else{
+
+ /**Elimina as sessões atuais*/
+ @session_destroy();
+
+ /**Gera um novo session_id*/
+ @session_regenerate_id();
+
+ return false;
+ }
+
+
+ }else{
+
+ /**Elimina as sessões atuais*/
+ @session_destroy();
+
+ /**Gera um novo session_id*/
+ @session_regenerate_id();
+
+ return false;
+ }
+
+ }
+
+ /** Inicializo a sessão */
+ public function SessionStart()
+ {
+
+ @session_start();
+
+ }
+
+ /** Finalizo a sessão */
+ public function SessionDestroy()
+ {
+
+ @session_destroy();
+
+ }
+
+ /** Função para carregar as informações */
+ public function LoadConfigPublic()
+ {
+
+ /** Carrego o arquivo de configuração */
+ return (object)json_decode(file_get_contents('config/config.json'));
+
+ }
+
+
+ /** Antiinjection */
+ public function antiInjectionArray($ar)
+ {
+
+ /** Verifica se a array foi informada */
+ if( is_array($ar) ){
+
+ $str = [];
+
+ foreach($ar as $value){
+
+ array_push($str, $this->antiInjection( $value ));
+
+ }
+
+ return $str;
+
+ }else{
+
+ return $ar;
+ }
+ }
+
+
+ /** Antiinjection */
+ public function antiInjection($string, string $long = '')
+ {
+
+ /** Parâmetros de entrada */
+ $this->string = $string;
+ $this->long = $long;
+
+ /** Verifico o tipo de entrada */
+ if (is_array($this->string)) {
+
+ /** Retorno o texto sem formatação */
+ $this->antiInjectionArray($this->string);
+
+ } elseif (strcmp($this->long, 'S') === 0) {
+
+ /** Retorno a string sem tratamento */
+ return $this->string;
+
+ } else {
+
+ /** Remoção de espaçamentos */
+ $this->string = trim($this->string);
+
+ /** Remoção de tags PHP e HTML */
+ $this->string = strip_tags($this->string);
+
+ /** Adição de barras invertidas */
+ $this->string = addslashes($this->string);
+
+ /** Evita ataque XSS */
+ $this->string = htmlspecialchars($this->string);
+
+ /** Elementos do SQL Injection */
+ $elements = array(
+ ' drop ' ,
+ ' select ' ,
+ ' delete ' ,
+ ' update ' ,
+ ' insert ' ,
+ ' alert ' ,
+ ' destroy ' ,
+ ' * ' ,
+ ' database ' ,
+ ' drop ' ,
+ ' union ' ,
+ ' TABLE_NAME ' ,
+ ' 1=1 ' ,
+ ' or 1 ' ,
+ ' exec ' ,
+ ' INFORMATION_SCHEMA ' ,
+ ' like ' ,
+ ' COLUMNS ' ,
+ ' into ' ,
+ ' VALUES ' ,
+ ' from ' ,
+ ' undefined '
+ );
+
+ /** Transformo as palavras em array */
+ $palavras = explode(' ', str_replace(',', '', $this->string));
+
+ /** Percorro todas as palavras localizadas */
+ foreach ($palavras as $keyPalavra => $palavra)
+ {
+
+ /** Percorro todos os elementos do SQL Injection */
+ foreach ($elements as $keyElement => $element)
+ {
+
+ /** Verifico se a palavra esta na lista negra */
+ if (strcmp(strtolower($palavra), strtolower($element)) === 0) {
+
+ /** Realizo a troca da marcação pela palavra qualificada */
+ $this->string = str_replace($palavra, '', $this->string);
+
+ }
+
+ }
+
+ }
+
+ /** Retorno o texto tratado */
+ return $this->string;
+
+ }
+
+
+ }
+
+ /** Criptografa uma string */
+ public function securedEncrypt($first_key, $second_key, $method, $str)
+ {
+ /** String a ser criptografada */
+ $data = $str;
+
+ $iv_length = openssl_cipher_iv_length($method);
+ $iv = openssl_random_pseudo_bytes($iv_length);
+
+ $first_encrypted = openssl_encrypt($data,$method,$first_key, OPENSSL_RAW_DATA ,$iv);
+ $second_encrypted = hash_hmac('sha3-512', $first_encrypted, $second_key, TRUE);
+
+ $output = base64_encode($iv.$second_encrypted.$first_encrypted);
+
+ return $output;
+ }
+
+ /** Descriptografa uma string */
+ public function securedDecrypt($first_key, $method, $input)
+ {
+ /** String a ser descriptografada */
+ $mix = base64_decode($input);
+
+ $iv_length = openssl_cipher_iv_length($method);
+
+ $iv = substr($mix,0,$iv_length);
+ $first_encrypted = substr($mix,$iv_length+64);
+
+ /** Descriptografa string */
+ $output = openssl_decrypt($first_encrypted,$method,$first_key,OPENSSL_RAW_DATA,$iv);
+
+ return $output;
+ }
+
+
+
+ /** paginação */
+ public function pagination(int $numberRecords, int $start, int $max, int $page, string $queryString, string $message, string $form=null)
+ {
+
+ /** Quantidade de registros junto ao banco de dados */
+ $this->numberRecords = $numberRecords;
+ $this->start = $start;
+ $this->max = $max;
+ $this->page = $page;
+ $this->queryString = $queryString;
+ $this->message = $message;
+ $this->form = $form;
+
+ /** Número de colunas para a paginação */
+ $this->pagination = $this->LoadConfigPublic()->{'app'}->{'datagrid'}->{'pagination'};
+
+ /** Define o número de colunas de acordo com a quantidade de registros */
+ $this->paginationColumns = ceil($this->numberRecords / $this->max);
+
+ /** Verifica se é para gerar a paginação */
+ if($this->paginationColumns > 1){
+
+ /** Prepara a paginação de registros */
+ $this->nav = '';
+
+ }
+
+ /** Retorna o objeto de paginação */
+ return $this->nav;
+ }
+
+ public function CentimeterToPoint($centimeter)
+ {
+
+ return $centimeter * 28.34645669;
+
+ }
+
+ /** Removedor de mascaras */
+ public function removeMask($string)
+ {
+
+ /** Elementos para serem removidos da String */
+ $this->elements = ['(', ')', '.', '-', '/'];
+
+ /** Parâmetros de entrada */
+ $this->string = $string;
+
+ /** Remoção dos elementos */
+ $this->string = str_replace($this->elements, '', $this->string);
+
+ return $this->string;
+
+ }
+
+ /** Formata as mascaras de uma marcação */
+ public function treatMask($str)
+ {
+
+ /** Verifica se a string a ser tratada foi informada */
+ if($str){
+
+ return ucwords(str_replace("_", " ", $str));
+
+ }
+
+ }
+
+
+ /** Validador de CPF */
+ public function validarCpf($string) {
+
+ // Extrai somente os números
+ $this->string = preg_replace( '/[^0-9]/is', '', $this->string);
+
+ // Verifica se foi informado todos os digitos corretamente
+ if (strlen($this->string) != 11) {
+ return false;
+ }
+
+ // Verifica se foi informada uma sequência de digitos repetidos. Ex: 111.111.111-11
+ if (preg_match('/(\d)\1{10}/', $this->string)) {
+ return false;
+ }
+
+ // Faz o calculo para validar o CPF
+ for ($t = 9; $t < 11; $t++) {
+ for ($d = 0, $c = 0; $c < $t; $c++) {
+ $d += $this->string[$c] * (($t + 1) - $c);
+ }
+ $d = ((10 * $d) % 11) % 10;
+ if ($this->string[$c] != $d) {
+ return false;
+ }
+ }
+ return true;
+
+ }
+
+
+ /** Limpa documento */
+ function ClearDoc($doc)
+ {
+ $d = str_replace(".", "", $doc);
+ $d = str_replace("/", "", $d);
+ $d = str_replace("-", "", $d);
+ $d = str_replace("_", "", $d);
+ $d = str_replace("(", "", $d);
+ $d = str_replace(")", "", $d);
+ $d = str_replace(" ", "", $d);
+
+ return $d;
+ }
+
+ /** Validar Email */
+ public function validarEmail($string)
+ {
+
+ /** Parâmetros dentrada */
+ $this->string = $string;
+
+ /** Verifico se o email esta válido */
+ if (filter_var($this->string, FILTER_VALIDATE_EMAIL))
+ {
+
+ return true;
+
+ }
+ else
+ {
+
+ return false;
+
+ }
+
+ }
+
+ /** Formata campo CPF/CNPJ */
+ public function formatarCPF_CNPJ($campo){
+
+ $tam = strlen($campo);
+
+ if($tam == 11)//Verifico se é um CPF
+ {
+ $part1 = substr($campo, 0, 3);
+ $part2 = substr($campo, 3, 3);
+ $part3 = substr($campo, 6, 3);
+ $part4 = substr($campo, 9, 2);
+
+ $return = $part1.'.'.$part2.'.'.$part3.'-'.$part4;//Monto o cpf formatado
+
+ }
+
+ elseif($tam == 14)//Verifico se é um CNPJ
+ {
+ $part1 = substr($campo, 0, 2);
+ $part2 = substr($campo, 2, 3);
+ $part3 = substr($campo, 5, 3);
+ $part4 = substr($campo, 8, 4);
+ $part5 = substr($campo, 12, 2);
+
+ $return = $part1.'.'.$part2.'.'.$part3.'/'.$part4.'-'.$part5;//Monto o cpf formatado
+ }
+
+ else
+ {
+ $return = $campo;
+ }
+
+ return $return;
+
+ }
+
+ /** Validador de Datas */
+ public function validaData($string){
+
+
+ if($string){
+
+ /** Parâmetros de entrada */
+ $this->string = $string;
+
+ $this->string = explode("/","$string"); // fatia a string $dat em pedados, usando / como referência
+ $d = $this->string[0];
+ $m = $this->string[1];
+ $y = $this->string[2];
+
+ // verifica se a data é válida!
+ // 1 = true (válida)
+ // 0 = false (inválida)
+ $res = checkdate($m,$d,$y);
+ if ($res == 1){
+
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+ }
+
+ /** Soma dias a uma data */
+ public function addDays($data, $days)
+ {
+
+ /** Parametros de entrada */
+ $this->data = $data;
+ $this->days = $days;
+
+ return strtotime($this->data. ' + '.$this->days.' days');
+ }
+
+ /** Retorna true caso a data de inicio seja menor que a data final */
+ public function trueDate($dateStart, $dateEnd)
+ {
+
+ $date1 = new \DateTime($dateStart);
+ $date2 = new \DateTime($dateEnd);
+
+ $bool = $date1 < $date2;
+
+ return $bool;
+ }
+
+ /** A retorna a diferença de dias entre datas */
+ public function numberDays($dateStart, $dateEnd)
+ {
+
+ //Retorna a diferença entre datas em dias corridos
+ return strtotime($dateStart) - strtotime($dateEnd);
+ }
+
+ /** A retorna a diferença de dias entre datas */
+ public function diffDate($dateStart, $dateEnd)
+ {
+
+ /** Parametros de entrada */
+ $this->dateStart = new \DateTime($dateStart);
+ $this->dateEnd = new \DateTime($dateEnd);
+ $this->interval = $this->dateStart->diff($this->dateEnd);
+
+ //Retorna a diferença entre datas em dias corridos
+ return $this->interval->days;
+ }
+
+
+ /**Retorna o tempo entre datas*/
+ public function checkTime($datahora)
+ {
+ /** Prepara a data de entrada para ser tratada */
+ $a_ano = substr($datahora, 0,4);
+ $a_mes = substr($datahora, 5,2);
+ $a_dia = substr($datahora, 8,2);
+ $a_hora = substr($datahora, 11,2);
+ $a_minuto = substr($datahora, 14,2);
+ $a_segundos = substr($datahora, 17,2);
+
+ // Obtém um timestamp Unix para a data informada
+ $dataacesso = mktime($a_hora, $a_minuto, $a_segundos, $a_mes, $a_dia, $a_ano);
+
+ // Pego a data atual
+ $dataatual = mktime(date('H'), date('i'), date('s'), date('m'), date('d'), date('Y'));
+
+ $return = (($dataatual - $dataacesso)/60);//Pego a diferença entre o tempo
+
+ return ceil($return);//Retorno a quantidade de minutos
+ }
+
+
+ /** Retorna o base64 de uma imagem a partir de sua URL */
+ public function imageB64($imageUrl)
+ {
+
+ /** Verifica se a url da imagem foi informada para efetuar o procedimento */
+ if($imageUrl){
+
+ /** Parametros de entrada */
+ $this->imageUrl = $imageUrl;
+
+ /** Carrega a url de uma determinada imagem */
+ $path = $this->imageUrl;
+
+ /** Recupera a extensão da imagem */
+ $type = pathinfo($path, PATHINFO_EXTENSION);
+
+ /** Carrega o buffer da imagem */
+ $data = file_get_contents($path);
+
+ /** Devolve a imagem em base64 já com as definições de visualização */
+ $base64 = 'data:image/' . $type . ';base64,' . base64_encode($data);
+
+ return $base64;
+
+ }
+
+ }
+
+ /**Trata valor para gravar no banco*/
+ public function MoeadDB($value)
+ {
+ if($value){
+
+ $v = str_replace(".", "", $value);
+ $v = str_replace(",", ".", $v);
+
+ return (float)$v;
+
+ }
+
+ }
+
+ /**Trata data no banco*/
+ public function DataDB($value)
+ {
+ if($value){
+
+ $d = explode("/", $value);
+ $date = $d[2].'-'.$d[1].'-'.$d[0];
+
+ return (string)$date;
+
+ }else{
+
+ return false;
+ }
+
+ }
+
+ /**Retorna o tempo entre datas em dias*/
+ public function CheckDay($datahora)
+ {
+ $a_ano = substr($datahora, 0,4);
+ $a_mes = substr($datahora, 5,2);
+ $a_dia = substr($datahora, 8,2);
+ $a_hora = substr($datahora, 11,2);
+ $a_minuto = substr($datahora, 14,2);
+ $a_segundos = substr($datahora, 17,2);
+
+ // Obtém um timestamp Unix para a data informada
+ $dataacesso = mktime((int)$a_hora, (int)$a_minuto, (int)$a_segundos, (int)$a_mes, (int)$a_dia, (int)$a_ano);
+
+ // Pego a data atual
+ $dataatual = mktime(date('H'), date('i'), date('s'), date('m'), date('d'), date('Y'));
+
+ $return = (($dataatual - $dataacesso)/(60 * 60 * 24));//Pego a diferença entre o tempo
+
+ return ceil($return);//Retorno a quantidade de dias
+ }
+
+
+ /** Gera uma senha aleatoriamente */
+ public function NewPassword()
+ {
+ /**SEQUENCIAS ALEATORIAS DE LETRAS E NUMEROS*/
+ $pwdtex = substr(str_shuffle('abcdefghijklmnpqrstuvxzwy'),0,3);
+ $pwdint = substr(str_shuffle('123456789'),0,3);
+ $pwdcar = substr(str_shuffle('@!_'),0,1);
+
+ /**PEGO A DATA E HORA ATUAL + OS MICROSEGUNDOS E CONVERTO PARA MD5*/
+ $data = substr(md5(date("dmYHis").substr(sprintf("%0.1f",microtime()),-1)),0,1);
+ $pwd = str_shuffle($pwdtex.$pwdint.$data.$pwdcar);//Gero a nova senha aleatoriamente
+
+ return $pwd;
+ }
+
+ /** Valida CPF/CNPJ */
+ public function cpfj($document) {
+ $l = strlen($document = str_replace(array(".","-","/"),"",$document));
+ if ((!is_numeric($document)) || (!in_array($l,array(11,14))) || (count(count_chars($document,1))==1)) {
+ return false;
+ }
+ $cpfj = str_split(substr($document,0,$l-2));
+ $k = 9;
+ $s = 0;
+ for ($j=0;$j<2;$j++) {
+ for ($i=(count($cpfj));$i>0;$i--) {
+ $s += $cpfj[$i-1] * $k;
+ $k--;
+ $l==14&&$k<2?$k=9:1;
+ }
+ $cpfj[] = $s%11==10?0:$s%11;
+ $s = 0;
+ $k = 9;
+ }
+ return $document==join($cpfj);
+ }
+
+ public function setzeros($valor, $qtde)
+ {
+ $result = $valor;
+ $tamanho = strlen($valor);
+ $valor = "";
+ for ($i=0; $i < $qtde-$tamanho;$i++)
+ {
+ $valor = "0" . $valor;
+ }
+ $result = $valor . $result;
+ return $result;
+ }
+
+ /** Validar data */
+ public function validateDate($date, $format = 'd/m/Y')
+ {
+ $d = \DateTime::createFromFormat($format, $date);
+ return $d && $d->format($format) == $date;
+ }
+
+ /** Validar hora */
+ public function validateHour($date, $format = 'H:i')
+ {
+ $d = \DateTime::createFromFormat($format, $date);
+ return $d && $d->format($format) == $date;
+ }
+
+
+ //Verificando se uma string possui letras e numeros
+ public function checkNumbers($senha)
+ {
+ //Converte a entrada para minusculo
+ $str = strtolower($senha);
+
+ /** Verifico se a senha possui letras e numeros */
+ if((preg_match('/[0-9]/', $str)) && (preg_match('/[a-z]/', $str)))
+ return true;
+ else
+ return false;
+
+ }
+
+ /** Encontra a posição da primeira ocorrência de uma string */
+ public function strPos(string $str, string $findme) : bool
+ {
+
+ /** Parametros de entrada */
+ $this->str = $str;
+ $this->findme = $findme;
+
+ /** Verifica a primeira ocorrência da string */
+ $this->pos = strpos($str, $findme);
+
+ /** Verifica se a string foi localizada */
+ if($this->pos === false){
+ return false;
+ }else{
+ return true;
+ }
+ }
+
+ /** Verifica se uma string é base64 */
+ function isBase64($string) {
+ // Verifica se a string possui um comprimento múltiplo de 4 e contém apenas caracteres válidos de base64
+ if (preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $string) && strlen($string) % 4 === 0) {
+ // Tenta decodificar a string
+ $decoded = base64_decode($string, true);
+ // Verifica se a string decodificada não é falsa e se, quando codificada novamente, é igual à original
+ return $decoded !== false && base64_encode($decoded) === $string;
+ }
+ return false;
+ }
+
+ /** VErifica se é um json válido */
+ function isValidJsonFile($filePath) {
+ // Verifica se o arquivo existe e é legível
+ if (!file_exists($filePath) || !is_readable($filePath)) {
+ return false;
+ }
+
+ // Lê o conteúdo do arquivo
+ $content = file_get_contents($filePath);
+
+ // Decodifica o conteúdo JSON
+ json_decode($content);
+
+ // Verifica se ocorreu algum erro na decodificação
+ return json_last_error() === JSON_ERROR_NONE;
+ }
+
+ /** Valida a senha */
+ public function validatePasswordStrength($pwd) {
+
+
+ /** Verifica se a senha de acesso precisa ter
+ * letras e números e pelo menos
+ * uma letra maiúscula ou minúscula
+ * e ter no mínimo oito(8) dígitos */
+ return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[\W_]{8,}$/', $pwd);
+
+ }
+
+ /** Gera um password hash */
+ public function passwordHash($pwd){
+
+ /** Parametros de entradas */
+ $this->pwd = $pwd;
+
+ /** Verifica se a senha foi informada */
+ if($this->pwd){
+
+ $hash = PASSWORD_DEFAULT;/** Padrão de criptogrfia */
+ $cost = array("cost"=>10);/** Nível de criptografia */
+
+ /** Gera o hash da senha */
+ return password_hash($this->pwd, $hash, $cost);
+
+ }
+
+ }
+
+
+ /** Remove caractes especiais */
+ public function cleanSpecialCharacters($string)
+ {
+ //Minusculas
+ $n = str_replace("ã", "a", $string);
+ $n = str_replace("à", "a", $n);
+
+ $n = str_replace("á", "a", $n);
+ $n = str_replace("é", "e", $n);
+ $n = str_replace("è", "e", $n);
+ $n = str_replace("ê", "e", $n);
+ $n = str_replace("í", "i", $n);
+ $n = str_replace("î", "i", $n);
+ $n = str_replace("õ", "o", $n);
+ $n = str_replace("ó", "o", $n);
+ $n = str_replace("ò", "o", $n);
+ $n = str_replace("ô", "o", $n);
+ $n = str_replace("ú", "u", $n);
+ $n = str_replace("ù", "u", $n);
+ $n = str_replace("ç", "c", $n);
+
+ //Maiusculas
+ $n = str_replace("Ã", "A", $n);
+ $n = str_replace("À", "A", $n);
+ $n = str_replace("Á", "A", $n);
+ $n = str_replace("É", "E", $n);
+ $n = str_replace("È", "E", $n);
+ $n = str_replace("Ê", "E", $n);
+ $n = str_replace("Í", "I", $n);
+ $n = str_replace("Î", "I", $n);
+ $n = str_replace("Õ", "O", $n);
+ $n = str_replace("Ó", "O", $n);
+ $n = str_replace("Ò", "O", $n);
+ $n = str_replace("Ô", "O", $n);
+ $n = str_replace("Ú", "U", $n);
+ $n = str_replace("Ù", "U", $n);
+ $n = str_replace("Ç", "C", $n);
+
+ //Caracteres Especiais
+ $n = str_replace("º", " ", $n);
+ $n = str_replace("ª", " ", $n);
+ $n = str_replace("&", " ", $n);
+ $n = str_replace("/", "-", $n);
+
+
+ return $n;
+ }
+
+ /** Substitui espações vazios por underline */
+ public function setUnderline($str){
+
+ return str_replace(" ", "_", $str);
+
+ }
+
+
+ /** Função que trata os nomes de funcoes */
+ public function nameFunction($str){
+
+ //TRATA A VARIAVEL
+ $var = explode(" ", strtolower($str));
+
+
+ $j=0;
+ $n=null;
+ foreach($var as $value){
+
+ if($j == 0){
+
+ $n .= $value;
+ $j++;
+
+ }elseif($j > 0){
+
+ $n .= ucwords($value);
+ $j++;
+ }
+ }
+
+ return $n;
+
+ unset($j);
+ unset($n);
+
+ }
+
+
+ /** Função que trata as variaveis */
+ public function trataString($str){
+
+ //TRATA A VARIAVEL
+ $var = explode("_", strtolower( str_replace("-", "_", str_replace(" ", "_", $str) ) ) );
+
+
+ $j=0;
+ $n=null;
+ foreach($var as $value){
+
+ if($j == 0){
+
+ $n .= $value;
+ $j++;
+
+ }elseif($j > 0){
+
+ $n .= ucwords($value);
+ $j++;
+ }
+ }
+
+ return $n;
+
+ unset($j);
+ unset($n);
+
+ }
+
+ /** Função que trata os nomes das class */
+ public function trataClass($str){
+
+ //TRATA A VARIAVEL
+ $var = explode("_", strtolower($str));
+
+
+ $j=0;
+ $n=null;
+ foreach($var as $value){
+
+ $n .= ucwords($value);
+ $j++;
+ }
+
+ return $n.".class.php";
+
+ unset($j);
+ unset($n);
+
+ }
+
+ /** Função que trata os nomes das class */
+ public function nameClass($str){
+
+ //TRATA A VARIAVEL
+ $var = explode("_", strtolower($str));
+
+
+ $j=0;
+ $n=null;
+ foreach($var as $value){
+
+ $n .= ucwords($value);
+ $j++;
+ }
+
+ return $n;
+
+ unset($j);
+ unset($n);
+
+ }
+
+ /** Gera o arquivo que não existe */
+ public function createFile($REQUEST, $FILE){
+
+
+ $lenght = 0;
+ $buffer = "";
+ $not = array('TABLE', 'ACTION', 'FOLDER', 'PHPSESSID');
+ $table = "";
+ $virgula = [];
+ $i = 0;
+
+ foreach($REQUEST as $key => $value){
+
+
+ /** Verifica se o tamanho da string é maior que o armazenado */
+ if(strlen($key) > $lenght){
+
+ $lenght = strlen($key);
+ }
+
+ /** Captura o nome da tabela */
+ if($key == 'TABLE'){
+
+ $table = $value;
+ }
+
+ if(!in_array($key, $not)){
+
+ if($i > 0){
+ array_push($virgula, ", ");
+ }
+
+ $i++;
+ }
+
+ }
+
+ $i = 1;
+
+ /** Inicio do arquivo */
+ $buffer .= "nameClass($table).";\r";
+ $buffer .= "use vendor\controller\\".$table."\\".$this->nameClass($table)."Validate;\r\r";
+
+ $buffer .= "try{\r\r";
+
+ $buffer .= ' /** Instânciamento de classes */'."\r";
+ $buffer .= " $".$this->nameClass($table)." = new ".$this->nameClass($table)."();\r";
+ $buffer .= " $".$this->nameClass($table)."Validate = new ".$this->nameClass($table)."Validate();\r\r";
+
+ $buffer .= ' /** Parametros de entrada */'."\r\n";
+
+ foreach($REQUEST as $key => $value){
+
+ if(!in_array($key, $not)){
+
+ //echo '\$'.$value;
+ $buffer .= ' $'.str_pad($this->trataString($key),$lenght, " ").'= isset($_POST[\''.$key.'\']) ? filter_input(INPUT_POST,\''.$key.'\', FILTER_SANITIZE_SPECIAL_CHARS) : '.(is_numeric($key) ? '0' : "''").";\r\n";
+ }
+ }
+
+ $buffer .= "\r\r";
+ $buffer .= " /** Validando os campos de entrada */\r";
+ foreach($REQUEST as $key => $value){
+
+ if(!in_array($key, $not)){
+
+ //echo '\$'.$value;
+ $buffer .= " $".$this->nameClass($table)."Validate->set".ucfirst($this->trataString($key))."(\$".$this->trataString($key).");\r";
+ }
+ }
+
+ $buffer .= "\r\r";
+ $buffer .= " /** Verifico a existência de erros */\r";
+ $buffer .= " if (!empty(\$".$this->nameClass($table)."Validate->getErrors())) {\r\r";
+
+ $buffer .= " /** Preparo o formulario para retorno **/\r";
+ $buffer .= " \$result = [\r\r";
+ $buffer .= " 'cod' => 0,\r";
+ $buffer .= " 'title' => 'Atenção',\r";
+ $buffer .= " 'message' => '
'.(\$".$this->nameClass($table)."Validate->get".ucfirst($this->trataString($table))."Id() > 0 ? 'Não foi possível atualizar o cadastro' : 'Não foi possível efetuar o cadastro') .'
';\r\r";
+
+ $buffer .= " /** Result **/\r";
+ $buffer .= " \$result = [\r\r";
+ $buffer .= " 'cod' => 0,\r";
+ $buffer .= " 'title' => 'Atenção',\r";
+ $buffer .= " 'message' => \$message,\r";
+ $buffer .= " 'redirect' => '',\r\r";
+ $buffer .= " ];\r\r";
+
+ $buffer .= " }\r\r";
+ $buffer .= " }\r\r";
+
+ $buffer .= " /** Envio **/\r";
+ $buffer .= " echo json_encode(\$result);\r\r";
+
+ $buffer .= " /** Paro o procedimento **/\r";
+ $buffer .= " exit;\r\r";
+
+
+
+ $buffer .= "}catch(Exception \$exception){\r\n\r\n";
+
+ $buffer .= " /** Preparo o formulario para retorno **/\r\n";
+ $buffer .= " \$result = [\r\n\r\n";
+
+ $buffer .= " 'cod' => 0,\r\n";
+ $buffer .= " 'message' => \$exception->getMessage(),\r\n";
+ $buffer .= " 'title' => 'Erro Interno',\r\n";
+ $buffer .= " 'type' => 'exception',\r\n\r\n";
+
+ $buffer .= " ];\r\n\r\n";
+
+ $buffer .= " /** Envio **/\r\n";
+ $buffer .= " echo json_encode(\$result);\r\n\r\n";
+
+ $buffer .= " /** Paro o procedimento **/\r\n";
+ $buffer .= " exit;\r\n";
+ $buffer .= "}";
+
+ /** Verifica se os diretorios existem */
+ if(!file_exists('vendor/'.$REQUEST['FOLDER'].'/'.$REQUEST['TABLE'])){
+
+ /** Cria os diretorios dos arquivos */
+ mkdir('vendor/'.$REQUEST['FOLDER'].'/'.$REQUEST['TABLE'], 0777, true);
+ }
+
+ $fp = fopen($FILE, 'w+');
+ fwrite($fp, $buffer);
+ fclose($fp);
+
+ }
+
+ /** Função para montar o nome de uma tabela a partir de uma biblioteca */
+ public function nameTable($library){
+
+ $table = "";
+
+ $str = str_split($library);
+
+ for($i=0; $idataType = $dataType;
+
+ if($this->dataType > 0){
+
+ switch ($this->dataType){
+
+ case 8: return 'INTEGER'; break;
+ case 7: return 'SMALL'; break;
+ case 10: return 'FLOAT'; break;
+ case 27: return 'DOUBLE'; break;
+ case 16: return 'NUMERIC'; break;
+ case 37: return 'VARCHAR'; break;
+ case 12: return 'DATE'; break;
+ case 13: return 'TIME'; break;
+ case 35: return 'TIMESTAMP'; break;
+ case 261: return 'BLOB'; break;
+ }
+
+ }
+
+ }
+
+ /** Função que retorna o tipo de variavel */
+ public function typeVar(string $parameterName){
+
+ /** Parametros de entrada */
+ $this->parameterName = $parameterName;
+
+ /** Verifica se o parametro foi informado */
+ if(!empty($this->parameterName)){
+
+ switch ($this->parameterName){
+
+ case 'INTEGER': return 'int'; break;
+ case 'SMALL': return 'string'; break;
+ case 'FLOAT': return 'float'; break;
+ case 'DOUBLE': return 'double'; break;
+ case 'NUMERIC': return 'int'; break;
+ case 'VARCHAR': return 'string'; break;
+ case 'DATE': return 'string'; break;
+ case 'TIME': return 'string'; break;
+ case 'TIMESTAMP': return 'string'; break;
+ case 'BLOB': return 'string'; break;
+ }
+
+ }
+
+ }
+
+ /** Retorna o mês informado pelo seu número */
+ public function returnMonth(int $month){
+
+
+ /** Parametros de entrada */
+ $this->month = (int)$month;
+
+ /** Verifica o mês informado */
+ switch($this->month){
+
+ case 1 : return 'Janeiro'; break;
+ case 2 : return 'Fevereiro'; break;
+ case 3 : return 'Março'; break;
+ case 4 : return 'Abril'; break;
+ case 5 : return 'Maio'; break;
+ case 6 : return 'Junho'; break;
+ case 7 : return 'Julho'; break;
+ case 8 : return 'Agosto'; break;
+ case 9 : return 'Setembro'; break;
+ case 10 : return 'Outubro'; break;
+ case 11 : return 'Novembro'; break;
+ case 12 : return 'Dezembro'; break;
+
+ }
+
+ }
+
+ function __destruct(){ }
+
+
+}
+
diff --git a/vendor/controller/routers/RouterValidate.class.php b/vendor/controller/routers/RouterValidate.class.php
new file mode 100644
index 0000000..855ab7f
--- /dev/null
+++ b/vendor/controller/routers/RouterValidate.class.php
@@ -0,0 +1,138 @@
+Main = new Main();
+
+ }
+
+ public function setTable(string $table): void
+ {
+
+ /** Tratamento da informação */
+ $this->table = strtolower(isset($table) ? $this->Main->antiInjection($table) : null);
+
+ /** Validação da informação */
+ if (empty($this->table)) {
+
+ /** Adiciono um elemento a array */
+ array_push($this->errors, ' O campo "Tabela", deve ser válido ');
+
+ }
+
+ }
+
+ public function setAction(string $action): void
+ {
+
+ /** Tratamento da informação */
+ $this->action = strtolower(isset($action) ? $this->Main->antiInjection($action) : null);
+
+ /** Validação da informação */
+ if (empty($this->action)) {
+
+ /** Adiciono um elemento a array */
+ array_push($this->errors, ' O campo "Ação", deve ser válido ');
+
+ }
+
+ }
+
+ public function setFolder(string $folder): void
+ {
+
+ /** Tratamento da informação */
+ $this->folder = strtolower(isset($folder) ? $this->Main->antiInjection($folder) : null);
+
+ /** Validação da informação */
+ if (empty($this->folder)) {
+
+ /** Adiciono um elemento a array */
+ array_push($this->errors, ' O campo "Pasta", deve ser válido ');
+
+ }
+
+ }
+
+ public function getTable(): string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->table;
+
+ }
+
+ public function getAction(): string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->action;
+
+ }
+
+ public function getFolder(): string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->folder;
+
+ }
+
+ public function getFullPath(): string
+ {
+
+ /** Retorno da informação */
+ return (string)'vendor/' . $this->getFolder() . '/' . $this->getTable() . '/' . $this->getAction() . '.php';
+
+ }
+
+ public function getErrors(): ? string
+ {
+
+ /** Verifico se deve informar os erros */
+ if (count($this->errors)) {
+
+ /** Verifica a quantidade de erros para informar a legenda */
+ $this->info = count($this->errors) > 1 ? '
Os seguintes erros foram encontrados
' : '
O seguinte erro foi encontrado
';
+
+ /** Lista os erros */
+ foreach ($this->errors as $keyError => $error) {
+
+ /** Monto a mensagem de erro */
+ $this->info .= '' . ($keyError + 1) . ' - ' . $error;
+
+ }
+
+ /** Retorno os erros encontrados */
+ return (string)$this->info;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/vendor/controller/station/StationValidate.class.php b/vendor/controller/station/StationValidate.class.php
new file mode 100644
index 0000000..4d61c1d
--- /dev/null
+++ b/vendor/controller/station/StationValidate.class.php
@@ -0,0 +1,515 @@
+Main = new Main();
+
+ }
+
+ /** Método trata campo station_id */
+ public function setStationId(int $stationId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->stationId = isset($stationId) ? $this->Main->antiInjection($stationId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->stationId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "station_id", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo client_id */
+ public function setClientId(int $clientId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->clientId = isset($clientId) ? $this->Main->antiInjection($clientId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->clientId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O cliente deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo user_id */
+ public function setUserId(int $userId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->userId = $userId > 0 ? (int)$this->Main->antiInjection($userId) : 0;
+
+ // /** Verifica se a informação foi informada */
+ // if(empty($this->userId))
+ // {
+
+ // /** Adição de elemento */
+ // array_push($this->errors, 'O campo "user_id", deve ser informado');
+
+ // }
+
+ }
+
+ /** Método trata campo decription */
+ public function setDescription(string $description) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->description = isset($description) ? $this->Main->antiInjection($description) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->description))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo descrição deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo type */
+ public function setType(string $type) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->type = isset($type) ? $this->Main->antiInjection($type) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->type))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O tipo de estação deve ser informado');
+
+ }
+
+ }
+
+
+ /** Método trata campo memory */
+ public function setMemory(string $memory) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->memory = isset($memory) ? $this->Main->antiInjection($memory) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->memory))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'A memória da estação deve ser informada');
+
+ }
+
+ }
+
+ /** Método trata campo cpu */
+ public function setCpu(string $cpu) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->cpu = isset($cpu) ? $this->Main->antiInjection($cpu) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->cpu))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'A CPU da estação deve ser informada');
+
+ }
+
+ }
+
+ /** Método trata campo type */
+ public function setOperatingSystem(string $operatingSystem) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->operatingSystem = isset($operatingSystem) ? $this->Main->antiInjection($operatingSystem) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->operatingSystem))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O sistema operacional deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo ip */
+ public function setIp(string $ip) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->ip = isset($ip) ? $this->Main->antiInjection($ip) : null;
+
+ // /** Verifica se a informação foi informada */
+ // if(empty($this->ip))
+ // {
+
+ // /** Adição de elemento */
+ // array_push($this->errors, 'O campo IP deve ser informado');
+
+ // }
+
+ }
+
+ /** Método trata campo port */
+ public function setPort(int $port) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->port = isset($port) ? $this->Main->antiInjection($port) : null;
+
+ // /** Verifica se a informação foi informada */
+ // if(empty($this->port))
+ // {
+
+ // /** Adição de elemento */
+ // array_push($this->errors, 'O campo porta deve ser informada');
+
+ // }
+
+ }
+
+ /** Método trata campo network_path */
+ public function setNetworkPath(string $networkPath) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->networkPath = isset($networkPath) ? $this->Main->antiInjection($networkPath) : null;
+
+ // /** Verifica se a informação foi informada */
+ // if(empty($this->networkPath))
+ // {
+
+ // /** Adição de elemento */
+ // array_push($this->errors, 'O campo caminho da rede deve ser informado');
+
+ // }
+
+ }
+
+ /** Método trata campo connection_name */
+ public function setConnectionName(string $connectionName) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->connectionName = isset($connectionName) ? $this->Main->antiInjection($connectionName) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->connectionName))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo nome software de conexão deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo connection_id */
+ public function setConnectionId(string $connectionId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->connectionId = isset($connectionId) ? $this->Main->antiInjection($connectionId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->connectionId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo ID da conexão deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo connection_user */
+ public function setConnectionUser(string $connectionUser) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->connectionUser = isset($connectionUser) ? $this->Main->antiInjection($connectionUser) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->connectionUser))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo usuário da conexão deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo connection_password */
+ public function setConnectionPassword(string $connectionPassword) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->connectionPassword = isset($connectionPassword) ? $this->Main->antiInjection($connectionPassword) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->connectionPassword))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo senha da conexão deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo observation */
+ public function setObservation(string $observation) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->observation = isset($observation) ? $this->Main->antiInjection($observation) : null;
+
+ // /** Verifica se a informação foi informada */
+ // if(empty($this->observation))
+ // {
+
+ // /** Adição de elemento */
+ // array_push($this->errors, 'O campo observação deve ser informado');
+
+ // }
+
+ }
+
+ /** Método retorna campo station_id */
+ public function getStationId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->stationId;
+
+ }
+
+ /** Método retorna campo client_id */
+ public function getClientId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->clientId;
+
+ }
+
+ /** Método retorna campo user_id */
+ public function getUserId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->userId;
+
+ }
+
+ /** Método retorna campo description */
+ public function getDescription() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->description;
+
+ }
+
+ /** Método retorna campo ip */
+ public function getIp() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->ip;
+
+ }
+
+ /** Método retorna campo type */
+ public function getType() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->type;
+
+ }
+
+ /** Método retorna campo Operating_System */
+ public function getOperatingSystem() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->operatingSystem;
+
+ }
+
+ /** Método retorna campo port */
+ public function getPort() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->port;
+
+ }
+
+ /** Método retorna campo cpu */
+ public function getCpu() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->cpu;
+
+ }
+
+ /** Método retorna campo memory */
+ public function getMemory() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->memory;
+
+ }
+
+ /** Método retorna campo network_path */
+ public function getNetworkPath() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->networkPath;
+
+ }
+
+ /** Método retorna campo connection_name */
+ public function getConnectionName() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->connectionName;
+
+ }
+
+ /** Método retorna campo connection_id */
+ public function getConnectionId() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->connectionId;
+
+ }
+
+ /** Método retorna campo connection_user */
+ public function getConnectionUser() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->connectionUser;
+
+ }
+
+ /** Método retorna campo connection_password */
+ public function getConnectionPassword() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->connectionPassword;
+
+ }
+
+ /** Método retorna campo observation */
+ public function getObservation() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->observation;
+
+ }
+
+ public function getErrors(): ? string
+ {
+
+ /** Verifico se deve informar os erros */
+ if (count($this->errors)) {
+
+ /** Verifica a quantidade de erros para informar a legenda */
+ $this->info = count($this->errors) > 1 ? '
Os seguintes erros foram encontrados
' : '
O seguinte erro foi encontrado
';
+
+ /** Lista os erros */
+ foreach ($this->errors as $keyError => $error) {
+
+ /** Monto a mensagem de erro */
+ $this->info .= '' . ($keyError + 1) . ' - ' . $error;
+
+ }
+
+ /** Retorno os erros encontrados */
+ return (string)$this->info;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ function __destruct(){}
+
+}
diff --git a/vendor/controller/station_disk/StationDiskValidate.class.php b/vendor/controller/station_disk/StationDiskValidate.class.php
new file mode 100644
index 0000000..8491c26
--- /dev/null
+++ b/vendor/controller/station_disk/StationDiskValidate.class.php
@@ -0,0 +1,275 @@
+Main = new Main();
+
+ }
+
/** Método trata campo station_disk_id */
+ public function setStationDiskId(int $stationDiskId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->stationDiskId = isset($stationDiskId) ? $this->Main->antiInjection($stationDiskId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->stationDiskId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "station_disk_id", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo station_id */
+ public function setStationId(int $stationId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->stationId = isset($stationId) ? $this->Main->antiInjection($stationId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->stationId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "station_id", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo description */
+ public function setDescription(string $description) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->description = isset($description) ? $this->Main->antiInjection($description) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->description))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "description", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo capacity */
+ public function setCapacity(string $capacity) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->capacity = isset($capacity) ? $this->Main->antiInjection($capacity) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->capacity))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "capacity", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo used */
+ public function setUsed(string $used) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->used = isset($used) ? $this->Main->antiInjection($used) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->used))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "used", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo available */
+ public function setAvailable(string $available) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->available = isset($available) ? $this->Main->antiInjection($available) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->available))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "available", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo available_percentage */
+ public function setAvailablePercentage(string $availablePercentage) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->availablePercentage = isset($availablePercentage) ? $this->Main->antiInjection($availablePercentage) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->availablePercentage))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "available_percentage", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo registration_date */
+ public function setRegistrationDate(string $registrationDate) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->registrationDate = isset($registrationDate) ? $this->Main->antiInjection($registrationDate) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->registrationDate))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "registration_date", deve ser informado');
+
+ }
+
+ }
+
+ /** Método retorna campo station_disk_id */
+ public function getStationDiskId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->stationDiskId;
+
+ }
+
+ /** Método retorna campo station_id */
+ public function getStationId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->stationId;
+
+ }
+
+ /** Método retorna campo description */
+ public function getDescription() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->description;
+
+ }
+
+ /** Método retorna campo capacity */
+ public function getCapacity() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->capacity;
+
+ }
+
+ /** Método retorna campo used */
+ public function getUsed() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->used;
+
+ }
+
+ /** Método retorna campo available */
+ public function getAvailable() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->available;
+
+ }
+
+ /** Método retorna campo available_percentage */
+ public function getAvailablePercentage() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->availablePercentage;
+
+ }
+
+ /** Método retorna campo registration_date */
+ public function getRegistrationDate() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->registrationDate;
+
+ }
+
+ public function getErrors(): ? string
+ {
+
+ /** Verifico se deve informar os erros */
+ if (count($this->errors)) {
+
+ /** Verifica a quantidade de erros para informar a legenda */
+ $this->info = count($this->errors) > 1 ? '
Os seguintes erros foram encontrados
' : '
O seguinte erro foi encontrado
';
+
+ /** Lista os erros */
+ foreach ($this->errors as $keyError => $error) {
+
+ /** Monto a mensagem de erro */
+ $this->info .= '' . ($keyError + 1) . ' - ' . $error;
+
+ }
+
+ /** Retorno os erros encontrados */
+ return (string)$this->info;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ function __destruct(){}
+
}
\ No newline at end of file
diff --git a/vendor/controller/station_folder/StationFolderValidate.class.php b/vendor/controller/station_folder/StationFolderValidate.class.php
new file mode 100644
index 0000000..68da982
--- /dev/null
+++ b/vendor/controller/station_folder/StationFolderValidate.class.php
@@ -0,0 +1,248 @@
+Main = new Main();
+
+ }
+
/** Método trata campo station_folder_id */
+ public function setStationFolderId(int $stationFolderId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->stationFolderId = isset($stationFolderId) ? $this->Main->antiInjection($stationFolderId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->stationFolderId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "station_folder_id", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo station_id */
+ public function setStationId(int $stationId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->stationId = isset($stationId) ? $this->Main->antiInjection($stationId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->stationId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "station_id", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo folder_path */
+ public function setFolderPath(string $folderPath) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->folderPath = isset($folderPath) ? $this->Main->antiInjection($folderPath) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->folderPath))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "folder_path", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo amount_of_files */
+ public function setAmountOfFiles(int $amountOfFiles) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->amountOfFiles = isset($amountOfFiles) ? $this->Main->antiInjection($amountOfFiles) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->amountOfFiles))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "amount_of_files", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo amount_of_files_current */
+ public function setAmountOfFilesCurrent(int $amountOfFilesCurrent) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->amountOfFilesCurrent = isset($amountOfFilesCurrent) ? $this->Main->antiInjection($amountOfFilesCurrent) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->amountOfFilesCurrent))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "amount_of_files_current", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo date_register */
+ public function setDateRegister(string $dateRegister) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->dateRegister = isset($dateRegister) ? $this->Main->antiInjection($dateRegister) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->dateRegister))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "date_register", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo last_update */
+ public function setLastUpdate(string $lastUpdate) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->lastUpdate = isset($lastUpdate) ? $this->Main->antiInjection($lastUpdate) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->lastUpdate))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "last_update", deve ser informado');
+
+ }
+
+ }
+
+ /** Método retorna campo station_folder_id */
+ public function getStationFolderId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->stationFolderId;
+
+ }
+
+ /** Método retorna campo station_id */
+ public function getStationId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->stationId;
+
+ }
+
+ /** Método retorna campo folder_path */
+ public function getFolderPath() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->folderPath;
+
+ }
+
+ /** Método retorna campo amount_of_files */
+ public function getAmountOfFiles() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->amountOfFiles;
+
+ }
+
+ /** Método retorna campo amount_of_files_current */
+ public function getAmountOfFilesCurrent() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->amountOfFilesCurrent;
+
+ }
+
+ /** Método retorna campo date_register */
+ public function getDateRegister() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->dateRegister;
+
+ }
+
+ /** Método retorna campo last_update */
+ public function getLastUpdate() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->lastUpdate;
+
+ }
+
+ public function getErrors(): ? string
+ {
+
+ /** Verifico se deve informar os erros */
+ if (count($this->errors)) {
+
+ /** Verifica a quantidade de erros para informar a legenda */
+ $this->info = count($this->errors) > 1 ? '
Os seguintes erros foram encontrados
' : '
O seguinte erro foi encontrado
';
+
+ /** Lista os erros */
+ foreach ($this->errors as $keyError => $error) {
+
+ /** Monto a mensagem de erro */
+ $this->info .= '' . ($keyError + 1) . ' - ' . $error;
+
+ }
+
+ /** Retorno os erros encontrados */
+ return (string)$this->info;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ function __destruct(){}
+
}
\ No newline at end of file
diff --git a/vendor/controller/user/UserValidate.class.php b/vendor/controller/user/UserValidate.class.php
new file mode 100644
index 0000000..29b05a0
--- /dev/null
+++ b/vendor/controller/user/UserValidate.class.php
@@ -0,0 +1,518 @@
+Main = new Main();
+
+ }
+
/** Método trata campo user_id */
+ public function setUserId(int $userId) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->userId = isset($userId) ? $this->Main->antiInjection($userId) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->userId))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "user_id", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo name_first */
+ public function setNameFirst(string $nameFirst) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->nameFirst = isset($nameFirst) ? $this->Main->antiInjection($nameFirst) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->nameFirst))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "name_first", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo name_last */
+ public function setNameLast(string $nameLast) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->nameLast = isset($nameLast) ? $this->Main->antiInjection($nameLast) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->nameLast))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "name_last", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo email */
+ public function setEmail(string $email) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->email = isset($email) ? $this->Main->antiInjection($email) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->email))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "email", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo password */
+ public function setPassword(string $password) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->password = isset($password) ? $this->Main->antiInjection($password) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->password))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "password", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo password_temp */
+ public function setPasswordTemp(string $passwordTemp) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->passwordTemp = isset($passwordTemp) ? $this->Main->antiInjection($passwordTemp) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->passwordTemp))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "password_temp", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo active */
+ public function setActive(string $active) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->active = isset($active) ? $this->Main->antiInjection($active) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->active))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "active", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo birth_date */
+ public function setBirthDate(string $birthDate) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->birthDate = isset($birthDate) ? $this->Main->antiInjection($birthDate) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->birthDate))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "birth_date", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo genre */
+ public function setGenre(string $genre) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->genre = isset($genre) ? $this->Main->antiInjection($genre) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->genre))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "genre", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo date_register */
+ public function setDateRegister(string $dateRegister) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->dateRegister = isset($dateRegister) ? $this->Main->antiInjection($dateRegister) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->dateRegister))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "date_register", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo access_first */
+ public function setAccessFirst(string $accessFirst) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->accessFirst = isset($accessFirst) ? $this->Main->antiInjection($accessFirst) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->accessFirst))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "access_first", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo access_last */
+ public function setAccessLast(string $accessLast) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->accessLast = isset($accessLast) ? $this->Main->antiInjection($accessLast) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->accessLast))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "access_last", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo administrator */
+ public function setAdministrator(string $administrator) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->administrator = isset($administrator) ? $this->Main->antiInjection($administrator) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->administrator))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "administrator", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo password_temp_confirm */
+ public function setPasswordTempConfirm(string $passwordTempConfirm) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->passwordTempConfirm = isset($passwordTempConfirm) ? $this->Main->antiInjection($passwordTempConfirm) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->passwordTempConfirm))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "password_temp_confirm", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo users_id_create */
+ public function setUsersIdCreate(int $usersIdCreate) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->usersIdCreate = isset($usersIdCreate) ? $this->Main->antiInjection($usersIdCreate) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->usersIdCreate))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "users_id_create", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo users_id_update */
+ public function setUsersIdUpdate(int $usersIdUpdate) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->usersIdUpdate = isset($usersIdUpdate) ? $this->Main->antiInjection($usersIdUpdate) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->usersIdUpdate))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "users_id_update", deve ser informado');
+
+ }
+
+ }
+
+ /** Método trata campo users_id_delete */
+ public function setUsersIdDelete(int $usersIdDelete) : void
+ {
+
+ /** Trata a entrada da informação */
+ $this->usersIdDelete = isset($usersIdDelete) ? $this->Main->antiInjection($usersIdDelete) : null;
+
+ /** Verifica se a informação foi informada */
+ if(empty($this->usersIdDelete))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "users_id_delete", deve ser informado');
+
+ }
+
+ }
+
+ /** Método retorna campo user_id */
+ public function getUserId() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->userId;
+
+ }
+
+ /** Método retorna campo name_first */
+ public function getNameFirst() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->nameFirst;
+
+ }
+
+ /** Método retorna campo name_last */
+ public function getNameLast() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->nameLast;
+
+ }
+
+ /** Método retorna campo email */
+ public function getEmail() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->email;
+
+ }
+
+ /** Método retorna campo password */
+ public function getPassword() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->password;
+
+ }
+
+ /** Método retorna campo password_temp */
+ public function getPasswordTemp() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->passwordTemp;
+
+ }
+
+ /** Método retorna campo active */
+ public function getActive() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->active;
+
+ }
+
+ /** Método retorna campo birth_date */
+ public function getBirthDate() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->birthDate;
+
+ }
+
+ /** Método retorna campo genre */
+ public function getGenre() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->genre;
+
+ }
+
+ /** Método retorna campo date_register */
+ public function getDateRegister() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->dateRegister;
+
+ }
+
+ /** Método retorna campo access_first */
+ public function getAccessFirst() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->accessFirst;
+
+ }
+
+ /** Método retorna campo access_last */
+ public function getAccessLast() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->accessLast;
+
+ }
+
+ /** Método retorna campo administrator */
+ public function getAdministrator() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->administrator;
+
+ }
+
+ /** Método retorna campo password_temp_confirm */
+ public function getPasswordTempConfirm() : ? string
+ {
+
+ /** Retorno da informação */
+ return (string)$this->passwordTempConfirm;
+
+ }
+
+ /** Método retorna campo users_id_create */
+ public function getUsersIdCreate() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->usersIdCreate;
+
+ }
+
+ /** Método retorna campo users_id_update */
+ public function getUsersIdUpdate() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->usersIdUpdate;
+
+ }
+
+ /** Método retorna campo users_id_delete */
+ public function getUsersIdDelete() : ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->usersIdDelete;
+
+ }
+
+ public function getErrors(): ? string
+ {
+
+ /** Verifico se deve informar os erros */
+ if (count($this->errors)) {
+
+ /** Verifica a quantidade de erros para informar a legenda */
+ $this->info = count($this->errors) > 1 ? '
Os seguintes erros foram encontrados
' : '
O seguinte erro foi encontrado
';
+
+ /** Lista os erros */
+ foreach ($this->errors as $keyError => $error) {
+
+ /** Monto a mensagem de erro */
+ $this->info .= '' . ($keyError + 1) . ' - ' . $error;
+
+ }
+
+ /** Retorno os erros encontrados */
+ return (string)$this->info;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ function __destruct(){}
+
}
\ No newline at end of file
diff --git a/vendor/controller/users/UsersValidate.class.php b/vendor/controller/users/UsersValidate.class.php
new file mode 100644
index 0000000..a4cacaa
--- /dev/null
+++ b/vendor/controller/users/UsersValidate.class.php
@@ -0,0 +1,431 @@
+Main = new Main();
+
+ }
+
+ public function setUsersId(int $usersId): void
+ {
+
+ /** Tratamento da informação */
+ $this->usersId = $usersId > 0 ? (int)$this->Main->antiInjection($usersId) : 0;
+
+ /** Validação da informação */
+ if ($this->usersId < 0)
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "Usuário ID", deve ser válido');
+
+ }
+
+ }
+
+ public function setClientsId(int $clientsId): void
+ {
+
+ /** Tratamento da informação */
+ $this->clientsId = $clientsId > 0 ? (int)$this->Main->antiInjection($clientsId) : 0;
+
+ }
+
+ public function setCompanyId(int $companyId) : void
+ {
+
+ /** Tratamento das informações */
+ $this->companyId = $this->Main->antiInjection($companyId);
+
+ /** Validação da informação */
+ if ($this->companyId <= 0)
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "Empresa ID", deve ser válido');
+
+ }
+
+ }
+
+ public function setNameFirst(string $nameFirst) : void
+ {
+
+ /** Tratamento das informações */
+ $this->nameFirst = $this->Main->antiInjection($nameFirst);
+
+ /** Validação da informação */
+ if (empty($this->nameFirst))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "Primeiro Nome", deve ser preenchido');
+
+ }
+
+ }
+
+ public function setNameLast(string $nameLast) : void
+ {
+
+ /** Tratamento das informações */
+ $this->nameLast = $this->Main->antiInjection($nameLast);
+
+ /** Validação da informação */
+ if (empty($this->nameLast))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "Último Nome", deve ser preenchido');
+
+ }
+
+ }
+
+ public function setEmail(string $email) : void
+ {
+
+ /** Tratamento das informações */
+ $this->email = $this->Main->antiInjection($email);
+
+ /** Validação da informação */
+ if (empty($this->email))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "Email", deve ser preenchido');
+
+ /** Verifica se o e-mail informado é válido */
+ }else if(!$this->Main->validarEmail($email)){
+
+ /** Adição de elemento */
+ array_push($this->errors, 'Informe um "Email" válido');
+ }
+
+ }
+
+ public function setBirthDate(string $birthDate) : void
+ {
+
+ /** Tratamento das informações */
+ $this->birthDate = isset($birthDate) ? $this->Main->antiInjection($birthDate) : '';
+
+ /** Validação da informação */
+ if (empty($this->birthDate))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "Data de Nascimento", deve ser preenchido');
+
+ }
+
+ }
+
+ public function setGenre(string $genre) : void
+ {
+
+ /** Tratamento das informações */
+ $this->genre = $this->Main->antiInjection($genre);
+
+ /** Validação da informação */
+ if (empty($this->genre))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "Gênero", deve ser preenchido');
+
+ }
+
+ }
+
+ public function setActive(string $active) : void
+ {
+
+ /** Tratamento das informações */
+ $this->active = $this->Main->antiInjection($active);
+
+ /** Validação da informação */
+ if (empty($this->active))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "Ativo", deve ser preenchido');
+
+ }
+
+ }
+
+ public function setAdministrator(string $administrator) : void
+ {
+
+ /** Tratamento das informações */
+ $this->administrator = $this->Main->antiInjection($administrator);
+
+ /** Validação da informação */
+ if (empty($this->administrator))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "Administrador", deve ser preenchido');
+
+ }
+
+ }
+
+ public function setPasswordTempConfirm(string $password_temp_confirm) : void
+ {
+
+ /** Tratamento das informações */
+ $this->passwordTempConfirm = $this->Main->antiInjection($password_temp_confirm);
+
+ }
+
+ public function setPasswordTemp(string $passwordTemp) : void
+ {
+
+ /** Tratamento das informações */
+ $this->passwordTemp = $this->Main->antiInjection($passwordTemp);
+
+ /** Verifica se é para validar a senha temporária */
+ if($this->passwordTempConfirm === 'S'){
+
+ /** Validação da informação */
+ if (empty($this->passwordTemp))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "Senha Temporária", deve ser preenchido');
+
+ }
+
+ }
+
+ }
+
+ public function setPassword(string $password) : void
+ {
+
+ /** Tratamento das informações */
+ $this->password = $this->Main->antiInjection($password);
+
+ /** Verifica se é para validar a senha temporária */
+ if( ($this->passwordTempConfirm === 'S') || ($this->passwordTempConfirm === null) ){
+
+ /** Validação da informação */
+ if (empty($this->password))
+ {
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "Senha", deve ser preenchido');
+
+ }
+
+ }
+
+ }
+
+ public function setPasswordConfirm(string $passwordConfirm) : void
+ {
+
+ /** Tratamento das informações */
+ $this->passwordConfirm = $this->Main->antiInjection($passwordConfirm);
+
+ /** Verifica se a confirmação da senha foi informada */
+ if( empty($this->passwordConfirm) ){
+
+ /** Adição de elemento */
+ array_push($this->errors, 'O campo "Confirmar senha", deve ser preenchido');
+
+ /** Verifica se a senha informada confere com a confirmação da senha */
+ }else{
+
+ /** Verifica se a senhas são idênticas */
+ if(trim($this->password) !== trim($this->passwordConfirm)){
+
+ /** Adição de elemento */
+ array_push($this->errors, 'As senhas informadas não conferem.');
+
+ /** Verifica se a senha informada contém os caracteres necessários */
+ }elseif( !$this->Main->validatePasswordStrength($this->password) ){
+
+ /** Adição de elemento */
+ array_push($this->errors, 'A senha de acesso precisa ter letras e números e pelo menos uma letra maiúscula ou minúscula e ter no mínimo oito(8) dígitos e no máximo dez(10) dígitos.');
+
+ }
+
+ }
+
+ }
+
+ public function getUserId(): ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->usersId;
+
+ }
+
+ public function getClientsId(): ? int
+ {
+
+ /** Retorno da informação */
+ return (int)$this->clientsId;
+
+ }
+
+ public function getUsersId() : ? int
+ {
+
+ return (int)$this->usersId;
+
+ }
+
+ public function getCompanyId() : ? int
+ {
+
+ return (int)$this->companyId;
+
+ }
+
+ /** Retorna o primeiro nome do usuário criptografado */
+ public function getNameFirst() : ? string
+ {
+
+ /** Retorna name_first criptografado */
+ return $this->Main->encryptData($this->nameFirst);
+
+ }
+
+ /** Retorna o segundo nome do usuário criptografado */
+ public function getNameLast() : ? string
+ {
+
+ /** Retorna name_last criptografado */
+ return $this->Main->encryptData($this->nameLast);
+
+ }
+
+ /** Retorna o email do usuário criptografado */
+ public function getEmail() : ? string
+ {
+
+ /** Retorna email criptografado */
+ return $this->email;
+
+ }
+
+ public function getBirthDate() : ? string
+ {
+
+ return (string)$this->Main->DataDB($this->birthDate);
+
+ }
+
+ public function getGenre() : ? string
+ {
+
+ return $this->genre;
+
+ }
+
+ public function getActive() : ? string
+ {
+
+ return $this->active;
+
+ }
+
+ public function getAdministrator() : ? string
+ {
+
+ return $this->administrator;
+
+ }
+
+ public function getPasswordTempConfirm() : ? string
+ {
+
+ return $this->passwordTempConfirm;
+ }
+
+ public function getPasswordTemp() : ? string
+ {
+
+ return (string)$this->passwordTemp;
+
+ }
+
+ public function getPassword() : ? string
+ {
+
+ return (string)$this->password;
+
+ }
+
+ public function getErrors(): ? string
+ {
+
+ /** Verifico se deve informar os erros */
+ if (count($this->errors)) {
+
+ /** Verifica a quantidade de erros para informar a legenda */
+ $this->info = count($this->errors) > 1 ? '
Os seguintes erros foram encontrados
' : '
O seguinte erro foi encontrado
';
+
+ /** Lista os erros */
+ foreach ($this->errors as $keyError => $error) {
+
+ /** Monto a mensagem de erro */
+ $this->info .= '' . ($keyError + 1) . ' - ' . $error;
+
+ }
+
+ /** Retorno os erros encontrados */
+ return (string)$this->info;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ /** destrutor da classe */
+ public function __destruct(){}
+
+}
\ No newline at end of file
diff --git a/vendor/library/Excel/Writer.php b/vendor/library/Excel/Writer.php
new file mode 100644
index 0000000..d62e9cf
--- /dev/null
+++ b/vendor/library/Excel/Writer.php
@@ -0,0 +1,104 @@
+
+*
+* PERL Spreadsheet::WriteExcel module.
+*
+* The author of the Spreadsheet::WriteExcel module is John McNamara
+*
+*
+* I _DO_ maintain this code, and John McNamara has nothing to do with the
+* porting of this code to PHP. Any questions directly related to this
+* class library should be directed to me.
+*
+* License Information:
+*
+* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
+* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+require_once 'PEAR.php';
+require_once 'Spreadsheet/Excel/Writer/Workbook.php';
+
+/**
+* Class for writing Excel Spreadsheets. This class should change COMPLETELY.
+*
+* @author Xavier Noguer
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+
+class Spreadsheet_Excel_Writer extends Spreadsheet_Excel_Writer_Workbook
+{
+ /**
+ * The constructor. It just creates a Workbook
+ *
+ * @param string $filename The optional filename for the Workbook.
+ * @return Spreadsheet_Excel_Writer_Workbook The Workbook created
+ */
+ function Spreadsheet_Excel_Writer($filename = '')
+ {
+ $this->_filename = $filename;
+ $this->Spreadsheet_Excel_Writer_Workbook($filename);
+ }
+
+ /**
+ * Send HTTP headers for the Excel file.
+ *
+ * @param string $filename The filename to use for HTTP headers
+ * @access public
+ */
+ function send($filename)
+ {
+ header("Content-type: application/vnd.ms-excel");
+ header("Content-Disposition: attachment; filename=\"$filename\"");
+ header("Expires: 0");
+ header("Cache-Control: must-revalidate, post-check=0,pre-check=0");
+ header("Pragma: public");
+ }
+
+ /**
+ * Utility function for writing formulas
+ * Converts a cell's coordinates to the A1 format.
+ *
+ * @access public
+ * @static
+ * @param integer $row Row for the cell to convert (0-indexed).
+ * @param integer $col Column for the cell to convert (0-indexed).
+ * @return string The cell identifier in A1 format
+ */
+ function rowcolToCell($row, $col)
+ {
+ if ($col > 255) { //maximum column value exceeded
+ return new PEAR_Error("Maximum column value exceeded: $col");
+ }
+
+ $int = (int)($col / 26);
+ $frac = $col % 26;
+ $chr1 = '';
+
+ if ($int > 0) {
+ $chr1 = chr(ord('A') + $int - 1);
+ }
+
+ $chr2 = chr(ord('A') + $frac);
+ $row++;
+
+ return $chr1 . $chr2 . $row;
+ }
+}
+?>
diff --git a/vendor/library/Excel/Writer/BIFFwriter.php b/vendor/library/Excel/Writer/BIFFwriter.php
new file mode 100644
index 0000000..c949b45
--- /dev/null
+++ b/vendor/library/Excel/Writer/BIFFwriter.php
@@ -0,0 +1,267 @@
+
+*
+* The majority of this is _NOT_ my code. I simply ported it from the
+* PERL Spreadsheet::WriteExcel module.
+*
+* The author of the Spreadsheet::WriteExcel module is John McNamara
+*
+*
+* I _DO_ maintain this code, and John McNamara has nothing to do with the
+* porting of this code to PHP. Any questions directly related to this
+* class library should be directed to me.
+*
+* License Information:
+*
+* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
+* Copyright (c) 2002-2003 Xavier Noguer xnoguer@php.net
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+require_once 'PEAR.php';
+
+/**
+* Class for writing Excel BIFF records.
+*
+* From "MICROSOFT EXCEL BINARY FILE FORMAT" by Mark O'Brien (Microsoft Corporation):
+*
+* BIFF (BInary File Format) is the file format in which Excel documents are
+* saved on disk. A BIFF file is a complete description of an Excel document.
+* BIFF files consist of sequences of variable-length records. There are many
+* different types of BIFF records. For example, one record type describes a
+* formula entered into a cell; one describes the size and location of a
+* window into a document; another describes a picture format.
+*
+* @author Xavier Noguer
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+
+class Spreadsheet_Excel_Writer_BIFFwriter extends PEAR
+{
+ /**
+ * The BIFF/Excel version (5).
+ * @var integer
+ */
+ var $_BIFF_version = 0x0500;
+
+ /**
+ * The byte order of this architecture. 0 => little endian, 1 => big endian
+ * @var integer
+ */
+ var $_byte_order;
+
+ /**
+ * The string containing the data of the BIFF stream
+ * @var string
+ */
+ var $_data;
+
+ /**
+ * The size of the data in bytes. Should be the same as strlen($this->_data)
+ * @var integer
+ */
+ var $_datasize;
+
+ /**
+ * The maximun length for a BIFF record. See _addContinue()
+ * @var integer
+ * @see _addContinue()
+ */
+ var $_limit;
+
+ /**
+ * The temporary dir for storing the OLE file
+ * @var string
+ */
+ var $_tmp_dir;
+
+ /**
+ * The temporary file for storing the OLE file
+ * @var string
+ */
+ var $_tmp_file;
+
+ /**
+ * Constructor
+ *
+ * @access public
+ */
+ function Spreadsheet_Excel_Writer_BIFFwriter()
+ {
+ $this->_byte_order = '';
+ $this->_data = '';
+ $this->_datasize = 0;
+ $this->_limit = 2080;
+ $this->_tmp_dir = '';
+ // Set the byte order
+ $this->_setByteOrder();
+ }
+
+ /**
+ * Determine the byte order and store it as class data to avoid
+ * recalculating it for each call to new().
+ *
+ * @access private
+ */
+ function _setByteOrder()
+ {
+ // Check if "pack" gives the required IEEE 64bit float
+ $teststr = pack("d", 1.2345);
+ $number = pack("C8", 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F);
+ if ($number == $teststr) {
+ $byte_order = 0; // Little Endian
+ } elseif ($number == strrev($teststr)){
+ $byte_order = 1; // Big Endian
+ } else {
+ // Give up. I'll fix this in a later version.
+ return $this->raiseError("Required floating point format ".
+ "not supported on this platform.");
+ }
+ $this->_byte_order = $byte_order;
+ }
+
+ /**
+ * General storage function
+ *
+ * @param string $data binary data to prepend
+ * @access private
+ */
+ function _prepend($data)
+ {
+ if (strlen($data) > $this->_limit) {
+ $data = $this->_addContinue($data);
+ }
+ $this->_data = $data.$this->_data;
+ $this->_datasize += strlen($data);
+ }
+
+ /**
+ * General storage function
+ *
+ * @param string $data binary data to append
+ * @access private
+ */
+ function _append($data)
+ {
+ if (strlen($data) > $this->_limit) {
+ $data = $this->_addContinue($data);
+ }
+ $this->_data = $this->_data.$data;
+ $this->_datasize += strlen($data);
+ }
+
+ /**
+ * Writes Excel BOF record to indicate the beginning of a stream or
+ * sub-stream in the BIFF file.
+ *
+ * @param integer $type Type of BIFF file to write: 0x0005 Workbook,
+ * 0x0010 Worksheet.
+ * @access private
+ */
+ function _storeBof($type)
+ {
+ $record = 0x0809; // Record identifier
+
+ // According to the SDK $build and $year should be set to zero.
+ // However, this throws a warning in Excel 5. So, use magic numbers.
+ if ($this->_BIFF_version == 0x0500) {
+ $length = 0x0008;
+ $unknown = '';
+ $build = 0x096C;
+ $year = 0x07C9;
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $length = 0x0010;
+ $unknown = pack("VV", 0x00000041, 0x00000006); //unknown last 8 bytes for BIFF8
+ $build = 0x0DBB;
+ $year = 0x07CC;
+ }
+ $version = $this->_BIFF_version;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvv", $version, $type, $build, $year);
+ $this->_prepend($header . $data . $unknown);
+ }
+
+ /**
+ * Writes Excel EOF record to indicate the end of a BIFF stream.
+ *
+ * @access private
+ */
+ function _storeEof()
+ {
+ $record = 0x000A; // Record identifier
+ $length = 0x0000; // Number of bytes to follow
+ $header = pack("vv", $record, $length);
+ $this->_append($header);
+ }
+
+ /**
+ * Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In
+ * Excel 97 the limit is 8228 bytes. Records that are longer than these limits
+ * must be split up into CONTINUE blocks.
+ *
+ * This function takes a long BIFF record and inserts CONTINUE records as
+ * necessary.
+ *
+ * @param string $data The original binary data to be written
+ * @return string A very convenient string of continue blocks
+ * @access private
+ */
+ function _addContinue($data)
+ {
+ $limit = $this->_limit;
+ $record = 0x003C; // Record identifier
+
+ // The first 2080/8224 bytes remain intact. However, we have to change
+ // the length field of the record.
+ $tmp = substr($data, 0, 2).pack("v", $limit-4).substr($data, 4, $limit - 4);
+
+ $header = pack("vv", $record, $limit); // Headers for continue records
+
+ // Retrieve chunks of 2080/8224 bytes +4 for the header.
+ $data_length = strlen($data);
+ for ($i = $limit; $i < ($data_length - $limit); $i += $limit) {
+ $tmp .= $header;
+ $tmp .= substr($data, $i, $limit);
+ }
+
+ // Retrieve the last chunk of data
+ $header = pack("vv", $record, strlen($data) - $i);
+ $tmp .= $header;
+ $tmp .= substr($data, $i, strlen($data) - $i);
+
+ return $tmp;
+ }
+
+ /**
+ * Sets the temp dir used for storing the OLE file
+ *
+ * @access public
+ * @param string $dir The dir to be used as temp dir
+ * @return true if given dir is valid, false otherwise
+ */
+ function setTempDir($dir)
+ {
+ if (is_dir($dir)) {
+ $this->_tmp_dir = $dir;
+ return true;
+ }
+ return false;
+ }
+}
+?>
diff --git a/vendor/library/Excel/Writer/Format.php b/vendor/library/Excel/Writer/Format.php
new file mode 100644
index 0000000..8922360
--- /dev/null
+++ b/vendor/library/Excel/Writer/Format.php
@@ -0,0 +1,1109 @@
+
+*
+* The majority of this is _NOT_ my code. I simply ported it from the
+* PERL Spreadsheet::WriteExcel module.
+*
+* The author of the Spreadsheet::WriteExcel module is John McNamara
+*
+*
+* I _DO_ maintain this code, and John McNamara has nothing to do with the
+* porting of this code to PHP. Any questions directly related to this
+* class library should be directed to me.
+*
+* License Information:
+*
+* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
+* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+require_once 'PEAR.php';
+
+/**
+* Class for generating Excel XF records (formats)
+*
+* @author Xavier Noguer
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+
+class Spreadsheet_Excel_Writer_Format extends PEAR
+{
+ /**
+ * The index given by the workbook when creating a new format.
+ * @var integer
+ */
+ var $_xf_index;
+
+ /**
+ * Index to the FONT record.
+ * @var integer
+ */
+ var $font_index;
+
+ /**
+ * The font name (ASCII).
+ * @var string
+ */
+ var $_font_name;
+
+ /**
+ * Height of font (1/20 of a point)
+ * @var integer
+ */
+ var $_size;
+
+ /**
+ * Bold style
+ * @var integer
+ */
+ var $_bold;
+
+ /**
+ * Bit specifiying if the font is italic.
+ * @var integer
+ */
+ var $_italic;
+
+ /**
+ * Index to the cell's color
+ * @var integer
+ */
+ var $_color;
+
+ /**
+ * The text underline property
+ * @var integer
+ */
+ var $_underline;
+
+ /**
+ * Bit specifiying if the font has strikeout.
+ * @var integer
+ */
+ var $_font_strikeout;
+
+ /**
+ * Bit specifiying if the font has outline.
+ * @var integer
+ */
+ var $_font_outline;
+
+ /**
+ * Bit specifiying if the font has shadow.
+ * @var integer
+ */
+ var $_font_shadow;
+
+ /**
+ * 2 bytes specifiying the script type for the font.
+ * @var integer
+ */
+ var $_font_script;
+
+ /**
+ * Byte specifiying the font family.
+ * @var integer
+ */
+ var $_font_family;
+
+ /**
+ * Byte specifiying the font charset.
+ * @var integer
+ */
+ var $_font_charset;
+
+ /**
+ * An index (2 bytes) to a FORMAT record (number format).
+ * @var integer
+ */
+ var $_num_format;
+
+ /**
+ * Bit specifying if formulas are hidden.
+ * @var integer
+ */
+ var $_hidden;
+
+ /**
+ * Bit specifying if the cell is locked.
+ * @var integer
+ */
+ var $_locked;
+
+ /**
+ * The three bits specifying the text horizontal alignment.
+ * @var integer
+ */
+ var $_text_h_align;
+
+ /**
+ * Bit specifying if the text is wrapped at the right border.
+ * @var integer
+ */
+ var $_text_wrap;
+
+ /**
+ * The three bits specifying the text vertical alignment.
+ * @var integer
+ */
+ var $_text_v_align;
+
+ /**
+ * 1 bit, apparently not used.
+ * @var integer
+ */
+ var $_text_justlast;
+
+ /**
+ * The two bits specifying the text rotation.
+ * @var integer
+ */
+ var $_rotation;
+
+ /**
+ * The cell's foreground color.
+ * @var integer
+ */
+ var $_fg_color;
+
+ /**
+ * The cell's background color.
+ * @var integer
+ */
+ var $_bg_color;
+
+ /**
+ * The cell's background fill pattern.
+ * @var integer
+ */
+ var $_pattern;
+
+ /**
+ * Style of the bottom border of the cell
+ * @var integer
+ */
+ var $_bottom;
+
+ /**
+ * Color of the bottom border of the cell.
+ * @var integer
+ */
+ var $_bottom_color;
+
+ /**
+ * Style of the top border of the cell
+ * @var integer
+ */
+ var $_top;
+
+ /**
+ * Color of the top border of the cell.
+ * @var integer
+ */
+ var $_top_color;
+
+ /**
+ * Style of the left border of the cell
+ * @var integer
+ */
+ var $_left;
+
+ /**
+ * Color of the left border of the cell.
+ * @var integer
+ */
+ var $_left_color;
+
+ /**
+ * Style of the right border of the cell
+ * @var integer
+ */
+ var $_right;
+
+ /**
+ * Color of the right border of the cell.
+ * @var integer
+ */
+ var $_right_color;
+
+ /**
+ * Constructor
+ *
+ * @access private
+ * @param integer $index the XF index for the format.
+ * @param array $properties array with properties to be set on initialization.
+ */
+ function Spreadsheet_Excel_Writer_Format($BIFF_version, $index = 0, $properties = array())
+ {
+ $this->_xf_index = $index;
+ $this->_BIFF_version = $BIFF_version;
+ $this->font_index = 0;
+ $this->_font_name = 'Arial';
+ $this->_size = 10;
+ $this->_bold = 0x0190;
+ $this->_italic = 0;
+ $this->_color = 0x7FFF;
+ $this->_underline = 0;
+ $this->_font_strikeout = 0;
+ $this->_font_outline = 0;
+ $this->_font_shadow = 0;
+ $this->_font_script = 0;
+ $this->_font_family = 0;
+ $this->_font_charset = 0;
+
+ $this->_num_format = 0;
+
+ $this->_hidden = 0;
+ $this->_locked = 0;
+
+ $this->_text_h_align = 0;
+ $this->_text_wrap = 0;
+ $this->_text_v_align = 2;
+ $this->_text_justlast = 0;
+ $this->_rotation = 0;
+
+ $this->_fg_color = 0x40;
+ $this->_bg_color = 0x41;
+
+ $this->_pattern = 0;
+
+ $this->_bottom = 0;
+ $this->_top = 0;
+ $this->_left = 0;
+ $this->_right = 0;
+ $this->_diag = 0;
+
+ $this->_bottom_color = 0x40;
+ $this->_top_color = 0x40;
+ $this->_left_color = 0x40;
+ $this->_right_color = 0x40;
+ $this->_diag_color = 0x40;
+
+ // Set properties passed to Spreadsheet_Excel_Writer_Workbook::addFormat()
+ foreach ($properties as $property => $value)
+ {
+ if (method_exists($this, 'set'.ucwords($property))) {
+ $method_name = 'set'.ucwords($property);
+ $this->$method_name($value);
+ }
+ }
+ }
+
+
+ /**
+ * Generate an Excel BIFF XF record (style or cell).
+ *
+ * @param string $style The type of the XF record ('style' or 'cell').
+ * @return string The XF record
+ */
+ function getXf($style)
+ {
+ // Set the type of the XF record and some of the attributes.
+ if ($style == 'style') {
+ $style = 0xFFF5;
+ } else {
+ $style = $this->_locked;
+ $style |= $this->_hidden << 1;
+ }
+
+ // Flags to indicate if attributes have been set.
+ $atr_num = ($this->_num_format != 0)?1:0;
+ $atr_fnt = ($this->font_index != 0)?1:0;
+ $atr_alc = ($this->_text_wrap)?1:0;
+ $atr_bdr = ($this->_bottom ||
+ $this->_top ||
+ $this->_left ||
+ $this->_right)?1:0;
+ $atr_pat = (($this->_fg_color != 0x40) ||
+ ($this->_bg_color != 0x41) ||
+ $this->_pattern)?1:0;
+ $atr_prot = $this->_locked | $this->_hidden;
+
+ // Zero the default border colour if the border has not been set.
+ if ($this->_bottom == 0) {
+ $this->_bottom_color = 0;
+ }
+ if ($this->_top == 0) {
+ $this->_top_color = 0;
+ }
+ if ($this->_right == 0) {
+ $this->_right_color = 0;
+ }
+ if ($this->_left == 0) {
+ $this->_left_color = 0;
+ }
+ if ($this->_diag == 0) {
+ $this->_diag_color = 0;
+ }
+
+ $record = 0x00E0; // Record identifier
+ if ($this->_BIFF_version == 0x0500) {
+ $length = 0x0010; // Number of bytes to follow
+ }
+ if ($this->_BIFF_version == 0x0600) {
+ $length = 0x0014;
+ }
+
+ $ifnt = $this->font_index; // Index to FONT record
+ $ifmt = $this->_num_format; // Index to FORMAT record
+ if ($this->_BIFF_version == 0x0500) {
+ $align = $this->_text_h_align; // Alignment
+ $align |= $this->_text_wrap << 3;
+ $align |= $this->_text_v_align << 4;
+ $align |= $this->_text_justlast << 7;
+ $align |= $this->_rotation << 8;
+ $align |= $atr_num << 10;
+ $align |= $atr_fnt << 11;
+ $align |= $atr_alc << 12;
+ $align |= $atr_bdr << 13;
+ $align |= $atr_pat << 14;
+ $align |= $atr_prot << 15;
+
+ $icv = $this->_fg_color; // fg and bg pattern colors
+ $icv |= $this->_bg_color << 7;
+
+ $fill = $this->_pattern; // Fill and border line style
+ $fill |= $this->_bottom << 6;
+ $fill |= $this->_bottom_color << 9;
+
+ $border1 = $this->_top; // Border line style and color
+ $border1 |= $this->_left << 3;
+ $border1 |= $this->_right << 6;
+ $border1 |= $this->_top_color << 9;
+
+ $border2 = $this->_left_color; // Border color
+ $border2 |= $this->_right_color << 7;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvvvvvv", $ifnt, $ifmt, $style, $align,
+ $icv, $fill,
+ $border1, $border2);
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $align = $this->_text_h_align; // Alignment
+ $align |= $this->_text_wrap << 3;
+ $align |= $this->_text_v_align << 4;
+ $align |= $this->_text_justlast << 7;
+
+ $used_attrib = $atr_num << 2;
+ $used_attrib |= $atr_fnt << 3;
+ $used_attrib |= $atr_alc << 4;
+ $used_attrib |= $atr_bdr << 5;
+ $used_attrib |= $atr_pat << 6;
+ $used_attrib |= $atr_prot << 7;
+
+ $icv = $this->_fg_color; // fg and bg pattern colors
+ $icv |= $this->_bg_color << 7;
+
+ $border1 = $this->_left; // Border line style and color
+ $border1 |= $this->_right << 4;
+ $border1 |= $this->_top << 8;
+ $border1 |= $this->_bottom << 12;
+ $border1 |= $this->_left_color << 16;
+ $border1 |= $this->_right_color << 23;
+ $diag_tl_to_rb = 0; // FIXME: add method
+ $diag_tr_to_lb = 0; // FIXME: add method
+ $border1 |= $diag_tl_to_rb << 30;
+ $border1 |= $diag_tr_to_lb << 31;
+
+ $border2 = $this->_top_color; // Border color
+ $border2 |= $this->_bottom_color << 7;
+ $border2 |= $this->_diag_color << 14;
+ $border2 |= $this->_diag << 21;
+ $border2 |= $this->_pattern << 26;
+
+ $header = pack("vv", $record, $length);
+
+ $rotation = $this->_rotation;
+ $biff8_options = 0x00;
+ $data = pack("vvvC", $ifnt, $ifmt, $style, $align);
+ $data .= pack("CCC", $rotation, $biff8_options, $used_attrib);
+ $data .= pack("VVv", $border1, $border2, $icv);
+ }
+
+ return($header . $data);
+ }
+
+ /**
+ * Generate an Excel BIFF FONT record.
+ *
+ * @return string The FONT record
+ */
+ function getFont()
+ {
+ $dyHeight = $this->_size * 20; // Height of font (1/20 of a point)
+ $icv = $this->_color; // Index to color palette
+ $bls = $this->_bold; // Bold style
+ $sss = $this->_font_script; // Superscript/subscript
+ $uls = $this->_underline; // Underline
+ $bFamily = $this->_font_family; // Font family
+ $bCharSet = $this->_font_charset; // Character set
+ $encoding = 0; // TODO: Unicode support
+
+ $cch = strlen($this->_font_name); // Length of font name
+ $record = 0x31; // Record identifier
+ if ($this->_BIFF_version == 0x0500) {
+ $length = 0x0F + $cch; // Record length
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $length = 0x10 + $cch;
+ }
+ $reserved = 0x00; // Reserved
+ $grbit = 0x00; // Font attributes
+ if ($this->_italic) {
+ $grbit |= 0x02;
+ }
+ if ($this->_font_strikeout) {
+ $grbit |= 0x08;
+ }
+ if ($this->_font_outline) {
+ $grbit |= 0x10;
+ }
+ if ($this->_font_shadow) {
+ $grbit |= 0x20;
+ }
+
+ $header = pack("vv", $record, $length);
+ if ($this->_BIFF_version == 0x0500) {
+ $data = pack("vvvvvCCCCC", $dyHeight, $grbit, $icv, $bls,
+ $sss, $uls, $bFamily,
+ $bCharSet, $reserved, $cch);
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $data = pack("vvvvvCCCCCC", $dyHeight, $grbit, $icv, $bls,
+ $sss, $uls, $bFamily,
+ $bCharSet, $reserved, $cch, $encoding);
+ }
+ return($header . $data . $this->_font_name);
+ }
+
+ /**
+ * Returns a unique hash key for a font.
+ * Used by Spreadsheet_Excel_Writer_Workbook::_storeAllFonts()
+ *
+ * The elements that form the key are arranged to increase the probability of
+ * generating a unique key. Elements that hold a large range of numbers
+ * (eg. _color) are placed between two binary elements such as _italic
+ *
+ * @return string A key for this font
+ */
+ function getFontKey()
+ {
+ $key = "$this->_font_name$this->_size";
+ $key .= "$this->_font_script$this->_underline";
+ $key .= "$this->_font_strikeout$this->_bold$this->_font_outline";
+ $key .= "$this->_font_family$this->_font_charset";
+ $key .= "$this->_font_shadow$this->_color$this->_italic";
+ $key = str_replace(' ', '_', $key);
+ return ($key);
+ }
+
+ /**
+ * Returns the index used by Spreadsheet_Excel_Writer_Worksheet::_XF()
+ *
+ * @return integer The index for the XF record
+ */
+ function getXfIndex()
+ {
+ return($this->_xf_index);
+ }
+
+ /**
+ * Used in conjunction with the set_xxx_color methods to convert a color
+ * string into a number. Color range is 0..63 but we will restrict it
+ * to 8..63 to comply with Gnumeric. Colors 0..7 are repeated in 8..15.
+ *
+ * @access private
+ * @param string $name_color name of the color (i.e.: 'blue', 'red', etc..). Optional.
+ * @return integer The color index
+ */
+ function _getColor($name_color = '')
+ {
+ $colors = array(
+ 'aqua' => 0x07,
+ 'cyan' => 0x07,
+ 'black' => 0x00,
+ 'blue' => 0x04,
+ 'brown' => 0x10,
+ 'magenta' => 0x06,
+ 'fuchsia' => 0x06,
+ 'gray' => 0x17,
+ 'grey' => 0x17,
+ 'green' => 0x11,
+ 'lime' => 0x03,
+ 'navy' => 0x12,
+ 'orange' => 0x35,
+ 'purple' => 0x14,
+ 'red' => 0x02,
+ 'silver' => 0x16,
+ 'white' => 0x01,
+ 'yellow' => 0x05
+ );
+
+ // Return the default color, 0x7FFF, if undef,
+ if ($name_color === '') {
+ return(0x7FFF);
+ }
+
+ // or the color string converted to an integer,
+ if (isset($colors[$name_color])) {
+ return($colors[$name_color]);
+ }
+
+ // or the default color if string is unrecognised,
+ if (preg_match("/\D/",$name_color)) {
+ return(0x7FFF);
+ }
+
+ // or the default color if arg is outside range,
+ if ($name_color > 63) {
+ return(0x7FFF);
+ }
+
+ // or an integer in the valid range
+ return($name_color);
+ }
+
+ /**
+ * Set cell alignment.
+ *
+ * @access public
+ * @param string $location alignment for the cell ('left', 'right', etc...).
+ */
+ function setAlign($location)
+ {
+ if (preg_match("/\d/",$location)) {
+ return; // Ignore numbers
+ }
+
+ $location = strtolower($location);
+
+ if ($location == 'left') {
+ $this->_text_h_align = 1;
+ }
+ if ($location == 'centre') {
+ $this->_text_h_align = 2;
+ }
+ if ($location == 'center') {
+ $this->_text_h_align = 2;
+ }
+ if ($location == 'right') {
+ $this->_text_h_align = 3;
+ }
+ if ($location == 'fill') {
+ $this->_text_h_align = 4;
+ }
+ if ($location == 'justify') {
+ $this->_text_h_align = 5;
+ }
+ if ($location == 'merge') {
+ $this->_text_h_align = 6;
+ }
+ if ($location == 'equal_space') { // For T.K.
+ $this->_text_h_align = 7;
+ }
+ if ($location == 'top') {
+ $this->_text_v_align = 0;
+ }
+ if ($location == 'vcentre') {
+ $this->_text_v_align = 1;
+ }
+ if ($location == 'vcenter') {
+ $this->_text_v_align = 1;
+ }
+ if ($location == 'bottom') {
+ $this->_text_v_align = 2;
+ }
+ if ($location == 'vjustify') {
+ $this->_text_v_align = 3;
+ }
+ if ($location == 'vequal_space') { // For T.K.
+ $this->_text_v_align = 4;
+ }
+ }
+
+ /**
+ * Set cell horizontal alignment.
+ *
+ * @access public
+ * @param string $location alignment for the cell ('left', 'right', etc...).
+ */
+ function setHAlign($location)
+ {
+ if (preg_match("/\d/",$location)) {
+ return; // Ignore numbers
+ }
+
+ $location = strtolower($location);
+
+ if ($location == 'left') {
+ $this->_text_h_align = 1;
+ }
+ if ($location == 'centre') {
+ $this->_text_h_align = 2;
+ }
+ if ($location == 'center') {
+ $this->_text_h_align = 2;
+ }
+ if ($location == 'right') {
+ $this->_text_h_align = 3;
+ }
+ if ($location == 'fill') {
+ $this->_text_h_align = 4;
+ }
+ if ($location == 'justify') {
+ $this->_text_h_align = 5;
+ }
+ if ($location == 'merge') {
+ $this->_text_h_align = 6;
+ }
+ if ($location == 'equal_space') { // For T.K.
+ $this->_text_h_align = 7;
+ }
+ }
+
+ /**
+ * Set cell vertical alignment.
+ *
+ * @access public
+ * @param string $location alignment for the cell ('top', 'vleft', 'vright', etc...).
+ */
+ function setVAlign($location)
+ {
+ if (preg_match("/\d/",$location)) {
+ return; // Ignore numbers
+ }
+
+ $location = strtolower($location);
+
+ if ($location == 'top') {
+ $this->_text_v_align = 0;
+ }
+ if ($location == 'vcentre') {
+ $this->_text_v_align = 1;
+ }
+ if ($location == 'vcenter') {
+ $this->_text_v_align = 1;
+ }
+ if ($location == 'bottom') {
+ $this->_text_v_align = 2;
+ }
+ if ($location == 'vjustify') {
+ $this->_text_v_align = 3;
+ }
+ if ($location == 'vequal_space') { // For T.K.
+ $this->_text_v_align = 4;
+ }
+ }
+
+ /**
+ * This is an alias for the unintuitive setAlign('merge')
+ *
+ * @access public
+ */
+ function setMerge()
+ {
+ $this->setAlign('merge');
+ }
+
+ /**
+ * Sets the boldness of the text.
+ * Bold has a range 100..1000.
+ * 0 (400) is normal. 1 (700) is bold.
+ *
+ * @access public
+ * @param integer $weight Weight for the text, 0 maps to 400 (normal text),
+ 1 maps to 700 (bold text). Valid range is: 100-1000.
+ It's Optional, default is 1 (bold).
+ */
+ function setBold($weight = 1)
+ {
+ if ($weight == 1) {
+ $weight = 0x2BC; // Bold text
+ }
+ if ($weight == 0) {
+ $weight = 0x190; // Normal text
+ }
+ if ($weight < 0x064) {
+ $weight = 0x190; // Lower bound
+ }
+ if ($weight > 0x3E8) {
+ $weight = 0x190; // Upper bound
+ }
+ $this->_bold = $weight;
+ }
+
+
+ /************************************
+ * FUNCTIONS FOR SETTING CELLS BORDERS
+ */
+
+ /**
+ * Sets the width for the bottom border of the cell
+ *
+ * @access public
+ * @param integer $style style of the cell border. 1 => thin, 2 => thick.
+ */
+ function setBottom($style)
+ {
+ $this->_bottom = $style;
+ }
+
+ /**
+ * Sets the width for the top border of the cell
+ *
+ * @access public
+ * @param integer $style style of the cell top border. 1 => thin, 2 => thick.
+ */
+ function setTop($style)
+ {
+ $this->_top = $style;
+ }
+
+ /**
+ * Sets the width for the left border of the cell
+ *
+ * @access public
+ * @param integer $style style of the cell left border. 1 => thin, 2 => thick.
+ */
+ function setLeft($style)
+ {
+ $this->_left = $style;
+ }
+
+ /**
+ * Sets the width for the right border of the cell
+ *
+ * @access public
+ * @param integer $style style of the cell right border. 1 => thin, 2 => thick.
+ */
+ function setRight($style)
+ {
+ $this->_right = $style;
+ }
+
+
+ /**
+ * Set cells borders to the same style
+ *
+ * @access public
+ * @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick.
+ */
+ function setBorder($style)
+ {
+ $this->setBottom($style);
+ $this->setTop($style);
+ $this->setLeft($style);
+ $this->setRight($style);
+ }
+
+
+ /*******************************************
+ * FUNCTIONS FOR SETTING CELLS BORDERS COLORS
+ */
+
+ /**
+ * Sets all the cell's borders to the same color
+ *
+ * @access public
+ * @param mixed $color The color we are setting. Either a string (like 'blue'),
+ * or an integer (range is [8...63]).
+ */
+ function setBorderColor($color)
+ {
+ $this->setBottomColor($color);
+ $this->setTopColor($color);
+ $this->setLeftColor($color);
+ $this->setRightColor($color);
+ }
+
+ /**
+ * Sets the cell's bottom border color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setBottomColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_bottom_color = $value;
+ }
+
+ /**
+ * Sets the cell's top border color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setTopColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_top_color = $value;
+ }
+
+ /**
+ * Sets the cell's left border color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setLeftColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_left_color = $value;
+ }
+
+ /**
+ * Sets the cell's right border color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setRightColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_right_color = $value;
+ }
+
+
+ /**
+ * Sets the cell's foreground color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setFgColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_fg_color = $value;
+ if ($this->_pattern == 0) { // force color to be seen
+ $this->_pattern = 1;
+ }
+ }
+
+ /**
+ * Sets the cell's background color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setBgColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_bg_color = $value;
+ if ($this->_pattern == 0) { // force color to be seen
+ $this->_pattern = 1;
+ }
+ }
+
+ /**
+ * Sets the cell's color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_color = $value;
+ }
+
+ /**
+ * Sets the fill pattern attribute of a cell
+ *
+ * @access public
+ * @param integer $arg Optional. Defaults to 1. Meaningful values are: 0-18,
+ * 0 meaning no background.
+ */
+ function setPattern($arg = 1)
+ {
+ $this->_pattern = $arg;
+ }
+
+ /**
+ * Sets the underline of the text
+ *
+ * @access public
+ * @param integer $underline The value for underline. Possible values are:
+ * 1 => underline, 2 => double underline.
+ */
+ function setUnderline($underline)
+ {
+ $this->_underline = $underline;
+ }
+
+ /**
+ * Sets the font style as italic
+ *
+ * @access public
+ */
+ function setItalic()
+ {
+ $this->_italic = 1;
+ }
+
+ /**
+ * Sets the font size
+ *
+ * @access public
+ * @param integer $size The font size (in pixels I think).
+ */
+ function setSize($size)
+ {
+ $this->_size = $size;
+ }
+
+ /**
+ * Sets text wrapping
+ *
+ * @access public
+ */
+ function setTextWrap()
+ {
+ $this->_text_wrap = 1;
+ }
+
+ /**
+ * Sets the orientation of the text
+ *
+ * @access public
+ * @param integer $angle The rotation angle for the text (clockwise). Possible
+ values are: 0, 90, 270 and -1 for stacking top-to-bottom.
+ */
+ function setTextRotation($angle)
+ {
+ switch ($angle)
+ {
+ case 0:
+ $this->_rotation = 0;
+ break;
+ case 90:
+ if ($this->_BIFF_version == 0x0500) {
+ $this->_rotation = 3;
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $this->_rotation = 180;
+ }
+ break;
+ case 270:
+ if ($this->_BIFF_version == 0x0500) {
+ $this->_rotation = 2;
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $this->_rotation = 90;
+ }
+ break;
+ case -1:
+ if ($this->_BIFF_version == 0x0500) {
+ $this->_rotation = 1;
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $this->_rotation = 255;
+ }
+ break;
+ default :
+ return $this->raiseError("Invalid value for angle.".
+ " Possible values are: 0, 90, 270 and -1 ".
+ "for stacking top-to-bottom.");
+ $this->_rotation = 0;
+ break;
+ }
+ }
+
+ /**
+ * Sets the numeric format.
+ * It can be date, time, currency, etc...
+ *
+ * @access public
+ * @param integer $num_format The numeric format.
+ */
+ function setNumFormat($num_format)
+ {
+ $this->_num_format = $num_format;
+ }
+
+ /**
+ * Sets font as strikeout.
+ *
+ * @access public
+ */
+ function setStrikeOut()
+ {
+ $this->_font_strikeout = 1;
+ }
+
+ /**
+ * Sets outlining for a font.
+ *
+ * @access public
+ */
+ function setOutLine()
+ {
+ $this->_font_outline = 1;
+ }
+
+ /**
+ * Sets font as shadow.
+ *
+ * @access public
+ */
+ function setShadow()
+ {
+ $this->_font_shadow = 1;
+ }
+
+ /**
+ * Sets the script type of the text
+ *
+ * @access public
+ * @param integer $script The value for script type. Possible values are:
+ * 1 => superscript, 2 => subscript.
+ */
+ function setScript($script)
+ {
+ $this->_font_script = $script;
+ }
+
+ /**
+ * Locks a cell.
+ *
+ * @access public
+ */
+ function setLocked()
+ {
+ $this->_locked = 1;
+ }
+
+ /**
+ * Unlocks a cell. Useful for unprotecting particular cells of a protected sheet.
+ *
+ * @access public
+ */
+ function setUnLocked()
+ {
+ $this->_locked = 0;
+ }
+
+ /**
+ * Sets the font family name.
+ *
+ * @access public
+ * @param string $fontfamily The font family name. Possible values are:
+ * 'Times New Roman', 'Arial', 'Courier'.
+ */
+ function setFontFamily($font_family)
+ {
+ $this->_font_name = $font_family;
+ }
+}
+?>
diff --git a/vendor/library/Excel/Writer/Parser.php b/vendor/library/Excel/Writer/Parser.php
new file mode 100644
index 0000000..bd93824
--- /dev/null
+++ b/vendor/library/Excel/Writer/Parser.php
@@ -0,0 +1,1703 @@
+"
+*/
+define('SPREADSHEET_EXCEL_WRITER_GT', ">");
+
+/**
+* @const SPREADSHEET_EXCEL_WRITER_LT token identifier for character "<"
+*/
+define('SPREADSHEET_EXCEL_WRITER_LT', "<");
+
+/**
+* @const SPREADSHEET_EXCEL_WRITER_LE token identifier for character "<="
+*/
+define('SPREADSHEET_EXCEL_WRITER_LE', "<=");
+
+/**
+* @const SPREADSHEET_EXCEL_WRITER_GE token identifier for character ">="
+*/
+define('SPREADSHEET_EXCEL_WRITER_GE', ">=");
+
+/**
+* @const SPREADSHEET_EXCEL_WRITER_EQ token identifier for character "="
+*/
+define('SPREADSHEET_EXCEL_WRITER_EQ', "=");
+
+/**
+* @const SPREADSHEET_EXCEL_WRITER_NE token identifier for character "<>"
+*/
+define('SPREADSHEET_EXCEL_WRITER_NE', "<>");
+
+/**
+* * @const SPREADSHEET_EXCEL_WRITER_CONCAT token identifier for character "&"
+*/
+define('SPREADSHEET_EXCEL_WRITER_CONCAT', "&");
+
+require_once 'PEAR.php';
+
+/**
+* Class for parsing Excel formulas
+*
+* @author Xavier Noguer
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+
+class Spreadsheet_Excel_Writer_Parser extends PEAR
+{
+ /**
+ * The index of the character we are currently looking at
+ * @var integer
+ */
+ var $_current_char;
+
+ /**
+ * The token we are working on.
+ * @var string
+ */
+ var $_current_token;
+
+ /**
+ * The formula to parse
+ * @var string
+ */
+ var $_formula;
+
+ /**
+ * The character ahead of the current char
+ * @var string
+ */
+ var $_lookahead;
+
+ /**
+ * The parse tree to be generated
+ * @var string
+ */
+ var $_parse_tree;
+
+ /**
+ * The byte order. 1 => big endian, 0 => little endian.
+ * @var integer
+ */
+ var $_byte_order;
+
+ /**
+ * Array of external sheets
+ * @var array
+ */
+ var $_ext_sheets;
+
+ /**
+ * Array of sheet references in the form of REF structures
+ * @var array
+ */
+ var $_references;
+
+ /**
+ * The BIFF version for the workbook
+ * @var integer
+ */
+ var $_BIFF_version;
+
+ /**
+ * The class constructor
+ *
+ * @param integer $byte_order The byte order (Little endian or Big endian) of the architecture
+ (optional). 1 => big endian, 0 (default) little endian.
+ */
+ function Spreadsheet_Excel_Writer_Parser($byte_order, $biff_version)
+ {
+ $this->_current_char = 0;
+ $this->_BIFF_version = $biff_version;
+ $this->_current_token = ''; // The token we are working on.
+ $this->_formula = ''; // The formula to parse.
+ $this->_lookahead = ''; // The character ahead of the current char.
+ $this->_parse_tree = ''; // The parse tree to be generated.
+ $this->_initializeHashes(); // Initialize the hashes: ptg's and function's ptg's
+ $this->_byte_order = $byte_order; // Little Endian or Big Endian
+ $this->_ext_sheets = array();
+ $this->_references = array();
+ }
+
+ /**
+ * Initialize the ptg and function hashes.
+ *
+ * @access private
+ */
+ function _initializeHashes()
+ {
+ // The Excel ptg indices
+ $this->ptg = array(
+ 'ptgExp' => 0x01,
+ 'ptgTbl' => 0x02,
+ 'ptgAdd' => 0x03,
+ 'ptgSub' => 0x04,
+ 'ptgMul' => 0x05,
+ 'ptgDiv' => 0x06,
+ 'ptgPower' => 0x07,
+ 'ptgConcat' => 0x08,
+ 'ptgLT' => 0x09,
+ 'ptgLE' => 0x0A,
+ 'ptgEQ' => 0x0B,
+ 'ptgGE' => 0x0C,
+ 'ptgGT' => 0x0D,
+ 'ptgNE' => 0x0E,
+ 'ptgIsect' => 0x0F,
+ 'ptgUnion' => 0x10,
+ 'ptgRange' => 0x11,
+ 'ptgUplus' => 0x12,
+ 'ptgUminus' => 0x13,
+ 'ptgPercent' => 0x14,
+ 'ptgParen' => 0x15,
+ 'ptgMissArg' => 0x16,
+ 'ptgStr' => 0x17,
+ 'ptgAttr' => 0x19,
+ 'ptgSheet' => 0x1A,
+ 'ptgEndSheet' => 0x1B,
+ 'ptgErr' => 0x1C,
+ 'ptgBool' => 0x1D,
+ 'ptgInt' => 0x1E,
+ 'ptgNum' => 0x1F,
+ 'ptgArray' => 0x20,
+ 'ptgFunc' => 0x21,
+ 'ptgFuncVar' => 0x22,
+ 'ptgName' => 0x23,
+ 'ptgRef' => 0x24,
+ 'ptgArea' => 0x25,
+ 'ptgMemArea' => 0x26,
+ 'ptgMemErr' => 0x27,
+ 'ptgMemNoMem' => 0x28,
+ 'ptgMemFunc' => 0x29,
+ 'ptgRefErr' => 0x2A,
+ 'ptgAreaErr' => 0x2B,
+ 'ptgRefN' => 0x2C,
+ 'ptgAreaN' => 0x2D,
+ 'ptgMemAreaN' => 0x2E,
+ 'ptgMemNoMemN' => 0x2F,
+ 'ptgNameX' => 0x39,
+ 'ptgRef3d' => 0x3A,
+ 'ptgArea3d' => 0x3B,
+ 'ptgRefErr3d' => 0x3C,
+ 'ptgAreaErr3d' => 0x3D,
+ 'ptgArrayV' => 0x40,
+ 'ptgFuncV' => 0x41,
+ 'ptgFuncVarV' => 0x42,
+ 'ptgNameV' => 0x43,
+ 'ptgRefV' => 0x44,
+ 'ptgAreaV' => 0x45,
+ 'ptgMemAreaV' => 0x46,
+ 'ptgMemErrV' => 0x47,
+ 'ptgMemNoMemV' => 0x48,
+ 'ptgMemFuncV' => 0x49,
+ 'ptgRefErrV' => 0x4A,
+ 'ptgAreaErrV' => 0x4B,
+ 'ptgRefNV' => 0x4C,
+ 'ptgAreaNV' => 0x4D,
+ 'ptgMemAreaNV' => 0x4E,
+ 'ptgMemNoMemN' => 0x4F,
+ 'ptgFuncCEV' => 0x58,
+ 'ptgNameXV' => 0x59,
+ 'ptgRef3dV' => 0x5A,
+ 'ptgArea3dV' => 0x5B,
+ 'ptgRefErr3dV' => 0x5C,
+ 'ptgAreaErr3d' => 0x5D,
+ 'ptgArrayA' => 0x60,
+ 'ptgFuncA' => 0x61,
+ 'ptgFuncVarA' => 0x62,
+ 'ptgNameA' => 0x63,
+ 'ptgRefA' => 0x64,
+ 'ptgAreaA' => 0x65,
+ 'ptgMemAreaA' => 0x66,
+ 'ptgMemErrA' => 0x67,
+ 'ptgMemNoMemA' => 0x68,
+ 'ptgMemFuncA' => 0x69,
+ 'ptgRefErrA' => 0x6A,
+ 'ptgAreaErrA' => 0x6B,
+ 'ptgRefNA' => 0x6C,
+ 'ptgAreaNA' => 0x6D,
+ 'ptgMemAreaNA' => 0x6E,
+ 'ptgMemNoMemN' => 0x6F,
+ 'ptgFuncCEA' => 0x78,
+ 'ptgNameXA' => 0x79,
+ 'ptgRef3dA' => 0x7A,
+ 'ptgArea3dA' => 0x7B,
+ 'ptgRefErr3dA' => 0x7C,
+ 'ptgAreaErr3d' => 0x7D
+ );
+
+ // Thanks to Michael Meeks and Gnumeric for the initial arg values.
+ //
+ // The following hash was generated by "function_locale.pl" in the distro.
+ // Refer to function_locale.pl for non-English function names.
+ //
+ // The array elements are as follow:
+ // ptg: The Excel function ptg code.
+ // args: The number of arguments that the function takes:
+ // >=0 is a fixed number of arguments.
+ // -1 is a variable number of arguments.
+ // class: The reference, value or array class of the function args.
+ // vol: The function is volatile.
+ //
+ $this->_functions = array(
+ // function ptg args class vol
+ 'COUNT' => array( 0, -1, 0, 0 ),
+ 'IF' => array( 1, -1, 1, 0 ),
+ 'ISNA' => array( 2, 1, 1, 0 ),
+ 'ISERROR' => array( 3, 1, 1, 0 ),
+ 'SUM' => array( 4, -1, 0, 0 ),
+ 'AVERAGE' => array( 5, -1, 0, 0 ),
+ 'MIN' => array( 6, -1, 0, 0 ),
+ 'MAX' => array( 7, -1, 0, 0 ),
+ 'ROW' => array( 8, -1, 0, 0 ),
+ 'COLUMN' => array( 9, -1, 0, 0 ),
+ 'NA' => array( 10, 0, 0, 0 ),
+ 'NPV' => array( 11, -1, 1, 0 ),
+ 'STDEV' => array( 12, -1, 0, 0 ),
+ 'DOLLAR' => array( 13, -1, 1, 0 ),
+ 'FIXED' => array( 14, -1, 1, 0 ),
+ 'SIN' => array( 15, 1, 1, 0 ),
+ 'COS' => array( 16, 1, 1, 0 ),
+ 'TAN' => array( 17, 1, 1, 0 ),
+ 'ATAN' => array( 18, 1, 1, 0 ),
+ 'PI' => array( 19, 0, 1, 0 ),
+ 'SQRT' => array( 20, 1, 1, 0 ),
+ 'EXP' => array( 21, 1, 1, 0 ),
+ 'LN' => array( 22, 1, 1, 0 ),
+ 'LOG10' => array( 23, 1, 1, 0 ),
+ 'ABS' => array( 24, 1, 1, 0 ),
+ 'INT' => array( 25, 1, 1, 0 ),
+ 'SIGN' => array( 26, 1, 1, 0 ),
+ 'ROUND' => array( 27, 2, 1, 0 ),
+ 'LOOKUP' => array( 28, -1, 0, 0 ),
+ 'INDEX' => array( 29, -1, 0, 1 ),
+ 'REPT' => array( 30, 2, 1, 0 ),
+ 'MID' => array( 31, 3, 1, 0 ),
+ 'LEN' => array( 32, 1, 1, 0 ),
+ 'VALUE' => array( 33, 1, 1, 0 ),
+ 'TRUE' => array( 34, 0, 1, 0 ),
+ 'FALSE' => array( 35, 0, 1, 0 ),
+ 'AND' => array( 36, -1, 0, 0 ),
+ 'OR' => array( 37, -1, 0, 0 ),
+ 'NOT' => array( 38, 1, 1, 0 ),
+ 'MOD' => array( 39, 2, 1, 0 ),
+ 'DCOUNT' => array( 40, 3, 0, 0 ),
+ 'DSUM' => array( 41, 3, 0, 0 ),
+ 'DAVERAGE' => array( 42, 3, 0, 0 ),
+ 'DMIN' => array( 43, 3, 0, 0 ),
+ 'DMAX' => array( 44, 3, 0, 0 ),
+ 'DSTDEV' => array( 45, 3, 0, 0 ),
+ 'VAR' => array( 46, -1, 0, 0 ),
+ 'DVAR' => array( 47, 3, 0, 0 ),
+ 'TEXT' => array( 48, 2, 1, 0 ),
+ 'LINEST' => array( 49, -1, 0, 0 ),
+ 'TREND' => array( 50, -1, 0, 0 ),
+ 'LOGEST' => array( 51, -1, 0, 0 ),
+ 'GROWTH' => array( 52, -1, 0, 0 ),
+ 'PV' => array( 56, -1, 1, 0 ),
+ 'FV' => array( 57, -1, 1, 0 ),
+ 'NPER' => array( 58, -1, 1, 0 ),
+ 'PMT' => array( 59, -1, 1, 0 ),
+ 'RATE' => array( 60, -1, 1, 0 ),
+ 'MIRR' => array( 61, 3, 0, 0 ),
+ 'IRR' => array( 62, -1, 0, 0 ),
+ 'RAND' => array( 63, 0, 1, 1 ),
+ 'MATCH' => array( 64, -1, 0, 0 ),
+ 'DATE' => array( 65, 3, 1, 0 ),
+ 'TIME' => array( 66, 3, 1, 0 ),
+ 'DAY' => array( 67, 1, 1, 0 ),
+ 'MONTH' => array( 68, 1, 1, 0 ),
+ 'YEAR' => array( 69, 1, 1, 0 ),
+ 'WEEKDAY' => array( 70, -1, 1, 0 ),
+ 'HOUR' => array( 71, 1, 1, 0 ),
+ 'MINUTE' => array( 72, 1, 1, 0 ),
+ 'SECOND' => array( 73, 1, 1, 0 ),
+ 'NOW' => array( 74, 0, 1, 1 ),
+ 'AREAS' => array( 75, 1, 0, 1 ),
+ 'ROWS' => array( 76, 1, 0, 1 ),
+ 'COLUMNS' => array( 77, 1, 0, 1 ),
+ 'OFFSET' => array( 78, -1, 0, 1 ),
+ 'SEARCH' => array( 82, -1, 1, 0 ),
+ 'TRANSPOSE' => array( 83, 1, 1, 0 ),
+ 'TYPE' => array( 86, 1, 1, 0 ),
+ 'ATAN2' => array( 97, 2, 1, 0 ),
+ 'ASIN' => array( 98, 1, 1, 0 ),
+ 'ACOS' => array( 99, 1, 1, 0 ),
+ 'CHOOSE' => array( 100, -1, 1, 0 ),
+ 'HLOOKUP' => array( 101, -1, 0, 0 ),
+ 'VLOOKUP' => array( 102, -1, 0, 0 ),
+ 'ISREF' => array( 105, 1, 0, 0 ),
+ 'LOG' => array( 109, -1, 1, 0 ),
+ 'CHAR' => array( 111, 1, 1, 0 ),
+ 'LOWER' => array( 112, 1, 1, 0 ),
+ 'UPPER' => array( 113, 1, 1, 0 ),
+ 'PROPER' => array( 114, 1, 1, 0 ),
+ 'LEFT' => array( 115, -1, 1, 0 ),
+ 'RIGHT' => array( 116, -1, 1, 0 ),
+ 'EXACT' => array( 117, 2, 1, 0 ),
+ 'TRIM' => array( 118, 1, 1, 0 ),
+ 'REPLACE' => array( 119, 4, 1, 0 ),
+ 'SUBSTITUTE' => array( 120, -1, 1, 0 ),
+ 'CODE' => array( 121, 1, 1, 0 ),
+ 'FIND' => array( 124, -1, 1, 0 ),
+ 'CELL' => array( 125, -1, 0, 1 ),
+ 'ISERR' => array( 126, 1, 1, 0 ),
+ 'ISTEXT' => array( 127, 1, 1, 0 ),
+ 'ISNUMBER' => array( 128, 1, 1, 0 ),
+ 'ISBLANK' => array( 129, 1, 1, 0 ),
+ 'T' => array( 130, 1, 0, 0 ),
+ 'N' => array( 131, 1, 0, 0 ),
+ 'DATEVALUE' => array( 140, 1, 1, 0 ),
+ 'TIMEVALUE' => array( 141, 1, 1, 0 ),
+ 'SLN' => array( 142, 3, 1, 0 ),
+ 'SYD' => array( 143, 4, 1, 0 ),
+ 'DDB' => array( 144, -1, 1, 0 ),
+ 'INDIRECT' => array( 148, -1, 1, 1 ),
+ 'CALL' => array( 150, -1, 1, 0 ),
+ 'CLEAN' => array( 162, 1, 1, 0 ),
+ 'MDETERM' => array( 163, 1, 2, 0 ),
+ 'MINVERSE' => array( 164, 1, 2, 0 ),
+ 'MMULT' => array( 165, 2, 2, 0 ),
+ 'IPMT' => array( 167, -1, 1, 0 ),
+ 'PPMT' => array( 168, -1, 1, 0 ),
+ 'COUNTA' => array( 169, -1, 0, 0 ),
+ 'PRODUCT' => array( 183, -1, 0, 0 ),
+ 'FACT' => array( 184, 1, 1, 0 ),
+ 'DPRODUCT' => array( 189, 3, 0, 0 ),
+ 'ISNONTEXT' => array( 190, 1, 1, 0 ),
+ 'STDEVP' => array( 193, -1, 0, 0 ),
+ 'VARP' => array( 194, -1, 0, 0 ),
+ 'DSTDEVP' => array( 195, 3, 0, 0 ),
+ 'DVARP' => array( 196, 3, 0, 0 ),
+ 'TRUNC' => array( 197, -1, 1, 0 ),
+ 'ISLOGICAL' => array( 198, 1, 1, 0 ),
+ 'DCOUNTA' => array( 199, 3, 0, 0 ),
+ 'ROUNDUP' => array( 212, 2, 1, 0 ),
+ 'ROUNDDOWN' => array( 213, 2, 1, 0 ),
+ 'RANK' => array( 216, -1, 0, 0 ),
+ 'ADDRESS' => array( 219, -1, 1, 0 ),
+ 'DAYS360' => array( 220, -1, 1, 0 ),
+ 'TODAY' => array( 221, 0, 1, 1 ),
+ 'VDB' => array( 222, -1, 1, 0 ),
+ 'MEDIAN' => array( 227, -1, 0, 0 ),
+ 'SUMPRODUCT' => array( 228, -1, 2, 0 ),
+ 'SINH' => array( 229, 1, 1, 0 ),
+ 'COSH' => array( 230, 1, 1, 0 ),
+ 'TANH' => array( 231, 1, 1, 0 ),
+ 'ASINH' => array( 232, 1, 1, 0 ),
+ 'ACOSH' => array( 233, 1, 1, 0 ),
+ 'ATANH' => array( 234, 1, 1, 0 ),
+ 'DGET' => array( 235, 3, 0, 0 ),
+ 'INFO' => array( 244, 1, 1, 1 ),
+ 'DB' => array( 247, -1, 1, 0 ),
+ 'FREQUENCY' => array( 252, 2, 0, 0 ),
+ 'ERROR.TYPE' => array( 261, 1, 1, 0 ),
+ 'REGISTER.ID' => array( 267, -1, 1, 0 ),
+ 'AVEDEV' => array( 269, -1, 0, 0 ),
+ 'BETADIST' => array( 270, -1, 1, 0 ),
+ 'GAMMALN' => array( 271, 1, 1, 0 ),
+ 'BETAINV' => array( 272, -1, 1, 0 ),
+ 'BINOMDIST' => array( 273, 4, 1, 0 ),
+ 'CHIDIST' => array( 274, 2, 1, 0 ),
+ 'CHIINV' => array( 275, 2, 1, 0 ),
+ 'COMBIN' => array( 276, 2, 1, 0 ),
+ 'CONFIDENCE' => array( 277, 3, 1, 0 ),
+ 'CRITBINOM' => array( 278, 3, 1, 0 ),
+ 'EVEN' => array( 279, 1, 1, 0 ),
+ 'EXPONDIST' => array( 280, 3, 1, 0 ),
+ 'FDIST' => array( 281, 3, 1, 0 ),
+ 'FINV' => array( 282, 3, 1, 0 ),
+ 'FISHER' => array( 283, 1, 1, 0 ),
+ 'FISHERINV' => array( 284, 1, 1, 0 ),
+ 'FLOOR' => array( 285, 2, 1, 0 ),
+ 'GAMMADIST' => array( 286, 4, 1, 0 ),
+ 'GAMMAINV' => array( 287, 3, 1, 0 ),
+ 'CEILING' => array( 288, 2, 1, 0 ),
+ 'HYPGEOMDIST' => array( 289, 4, 1, 0 ),
+ 'LOGNORMDIST' => array( 290, 3, 1, 0 ),
+ 'LOGINV' => array( 291, 3, 1, 0 ),
+ 'NEGBINOMDIST' => array( 292, 3, 1, 0 ),
+ 'NORMDIST' => array( 293, 4, 1, 0 ),
+ 'NORMSDIST' => array( 294, 1, 1, 0 ),
+ 'NORMINV' => array( 295, 3, 1, 0 ),
+ 'NORMSINV' => array( 296, 1, 1, 0 ),
+ 'STANDARDIZE' => array( 297, 3, 1, 0 ),
+ 'ODD' => array( 298, 1, 1, 0 ),
+ 'PERMUT' => array( 299, 2, 1, 0 ),
+ 'POISSON' => array( 300, 3, 1, 0 ),
+ 'TDIST' => array( 301, 3, 1, 0 ),
+ 'WEIBULL' => array( 302, 4, 1, 0 ),
+ 'SUMXMY2' => array( 303, 2, 2, 0 ),
+ 'SUMX2MY2' => array( 304, 2, 2, 0 ),
+ 'SUMX2PY2' => array( 305, 2, 2, 0 ),
+ 'CHITEST' => array( 306, 2, 2, 0 ),
+ 'CORREL' => array( 307, 2, 2, 0 ),
+ 'COVAR' => array( 308, 2, 2, 0 ),
+ 'FORECAST' => array( 309, 3, 2, 0 ),
+ 'FTEST' => array( 310, 2, 2, 0 ),
+ 'INTERCEPT' => array( 311, 2, 2, 0 ),
+ 'PEARSON' => array( 312, 2, 2, 0 ),
+ 'RSQ' => array( 313, 2, 2, 0 ),
+ 'STEYX' => array( 314, 2, 2, 0 ),
+ 'SLOPE' => array( 315, 2, 2, 0 ),
+ 'TTEST' => array( 316, 4, 2, 0 ),
+ 'PROB' => array( 317, -1, 2, 0 ),
+ 'DEVSQ' => array( 318, -1, 0, 0 ),
+ 'GEOMEAN' => array( 319, -1, 0, 0 ),
+ 'HARMEAN' => array( 320, -1, 0, 0 ),
+ 'SUMSQ' => array( 321, -1, 0, 0 ),
+ 'KURT' => array( 322, -1, 0, 0 ),
+ 'SKEW' => array( 323, -1, 0, 0 ),
+ 'ZTEST' => array( 324, -1, 0, 0 ),
+ 'LARGE' => array( 325, 2, 0, 0 ),
+ 'SMALL' => array( 326, 2, 0, 0 ),
+ 'QUARTILE' => array( 327, 2, 0, 0 ),
+ 'PERCENTILE' => array( 328, 2, 0, 0 ),
+ 'PERCENTRANK' => array( 329, -1, 0, 0 ),
+ 'MODE' => array( 330, -1, 2, 0 ),
+ 'TRIMMEAN' => array( 331, 2, 0, 0 ),
+ 'TINV' => array( 332, 2, 1, 0 ),
+ 'CONCATENATE' => array( 336, -1, 1, 0 ),
+ 'POWER' => array( 337, 2, 1, 0 ),
+ 'RADIANS' => array( 342, 1, 1, 0 ),
+ 'DEGREES' => array( 343, 1, 1, 0 ),
+ 'SUBTOTAL' => array( 344, -1, 0, 0 ),
+ 'SUMIF' => array( 345, -1, 0, 0 ),
+ 'COUNTIF' => array( 346, 2, 0, 0 ),
+ 'COUNTBLANK' => array( 347, 1, 0, 0 ),
+ 'ROMAN' => array( 354, -1, 1, 0 )
+ );
+ }
+
+ /**
+ * Convert a token to the proper ptg value.
+ *
+ * @access private
+ * @param mixed $token The token to convert.
+ * @return mixed the converted token on success. PEAR_Error if the token
+ * is not recognized
+ */
+ function _convert($token)
+ {
+ if (preg_match("/^\"[^\"]{0,255}\"$/", $token)) {
+ return $this->_convertString($token);
+
+ } elseif (is_numeric($token)) {
+ return $this->_convertNumber($token);
+
+ // match references like A1 or $A$1
+ } elseif (preg_match('/^\$?([A-Ia-i]?[A-Za-z])\$?(\d+)$/',$token)) {
+ return $this->_convertRef2d($token);
+
+ // match external references like Sheet1!A1 or Sheet1:Sheet2!A1
+ } elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z](\d+)$/u",$token)) {
+ return $this->_convertRef3d($token);
+
+ // match external references like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1
+ } elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z](\d+)$/u",$token)) {
+ return $this->_convertRef3d($token);
+
+ // match ranges like A1:B2
+ } elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)\:(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/",$token)) {
+ return $this->_convertRange2d($token);
+
+ // match ranges like A1..B2
+ } elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/",$token)) {
+ return $this->_convertRange2d($token);
+
+ // match external ranges like Sheet1!A1 or Sheet1:Sheet2!A1:B2
+ } elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?(\d+)\:([A-Ia-i]?[A-Za-z])?(\d+)$/u",$token)) {
+ return $this->_convertRange3d($token);
+
+ // match external ranges like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1:B2
+ } elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?(\d+)\:([A-Ia-i]?[A-Za-z])?(\d+)$/u",$token)) {
+ return $this->_convertRange3d($token);
+
+ // operators (including parentheses)
+ } elseif (isset($this->ptg[$token])) {
+ return pack("C", $this->ptg[$token]);
+
+ // commented so argument number can be processed correctly. See toReversePolish().
+ /*elseif (preg_match("/[A-Z0-9\xc0-\xdc\.]+/",$token))
+ {
+ return($this->_convertFunction($token,$this->_func_args));
+ }*/
+
+ // if it's an argument, ignore the token (the argument remains)
+ } elseif ($token == 'arg') {
+ return '';
+ }
+ // TODO: use real error codes
+ return $this->raiseError("Unknown token $token");
+ }
+
+ /**
+ * Convert a number token to ptgInt or ptgNum
+ *
+ * @access private
+ * @param mixed $num an integer or double for conversion to its ptg value
+ */
+ function _convertNumber($num)
+ {
+ // Integer in the range 0..2**16-1
+ if ((preg_match("/^\d+$/", $num)) and ($num <= 65535)) {
+ return pack("Cv", $this->ptg['ptgInt'], $num);
+ } else { // A float
+ if ($this->_byte_order) { // if it's Big Endian
+ $num = strrev($num);
+ }
+ return pack("Cd", $this->ptg['ptgNum'], $num);
+ }
+ }
+
+ /**
+ * Convert a string token to ptgStr
+ *
+ * @access private
+ * @param string $string A string for conversion to its ptg value.
+ * @return mixed the converted token on success. PEAR_Error if the string
+ * is longer than 255 characters.
+ */
+ function _convertString($string)
+ {
+ // chop away beggining and ending quotes
+ $string = substr($string, 1, strlen($string) - 2);
+ if (strlen($string) > 255) {
+ return $this->raiseError("String is too long");
+ }
+
+ if ($this->_BIFF_version == 0x0500) {
+ return pack("CC", $this->ptg['ptgStr'], strlen($string)).$string;
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $encoding = 0; // TODO: Unicode support
+ return pack("CCC", $this->ptg['ptgStr'], strlen($string), $encoding).$string;
+ }
+ }
+
+ /**
+ * Convert a function to a ptgFunc or ptgFuncVarV depending on the number of
+ * args that it takes.
+ *
+ * @access private
+ * @param string $token The name of the function for convertion to ptg value.
+ * @param integer $num_args The number of arguments the function receives.
+ * @return string The packed ptg for the function
+ */
+ function _convertFunction($token, $num_args)
+ {
+ $args = $this->_functions[$token][1];
+ $volatile = $this->_functions[$token][3];
+
+ // Fixed number of args eg. TIME($i,$j,$k).
+ if ($args >= 0) {
+ return pack("Cv", $this->ptg['ptgFuncV'], $this->_functions[$token][0]);
+ }
+ // Variable number of args eg. SUM($i,$j,$k, ..).
+ if ($args == -1) {
+ return pack("CCv", $this->ptg['ptgFuncVarV'], $num_args, $this->_functions[$token][0]);
+ }
+ }
+
+ /**
+ * Convert an Excel range such as A1:D4 to a ptgRefV.
+ *
+ * @access private
+ * @param string $range An Excel range in the A1:A2 or A1..A2 format.
+ */
+ function _convertRange2d($range, $class=0)
+ {
+
+ // TODO: possible class value 0,1,2 check Formula.pm
+ // Split the range into 2 cell refs
+ if (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\:([A-Ia-i]?[A-Za-z])(\d+)$/", $range)) {
+ list($cell1, $cell2) = explode(':', $range);
+ } elseif (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\.\.([A-Ia-i]?[A-Za-z])(\d+)$/", $range)) {
+ list($cell1, $cell2) = explode('..', $range);
+
+ } else {
+ // TODO: use real error codes
+ return $this->raiseError("Unknown range separator", 0, PEAR_ERROR_DIE);
+ }
+
+ // Convert the cell references
+ $cell_array1 = $this->_cellToPackedRowcol($cell1);
+ if (PEAR::isError($cell_array1)) {
+ return $cell_array1;
+ }
+ list($row1, $col1) = $cell_array1;
+ $cell_array2 = $this->_cellToPackedRowcol($cell2);
+ if (PEAR::isError($cell_array2)) {
+ return $cell_array2;
+ }
+ list($row2, $col2) = $cell_array2;
+
+ // The ptg value depends on the class of the ptg.
+ if ($class == 0) {
+ $ptgArea = pack("C", $this->ptg['ptgArea']);
+ } elseif ($class == 1) {
+ $ptgArea = pack("C", $this->ptg['ptgAreaV']);
+ } elseif ($class == 2) {
+ $ptgArea = pack("C", $this->ptg['ptgAreaA']);
+ } else {
+ // TODO: use real error codes
+ return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE);
+ }
+ return $ptgArea . $row1 . $row2 . $col1. $col2;
+ }
+
+ /**
+ * Convert an Excel 3d range such as "Sheet1!A1:D4" or "Sheet1:Sheet2!A1:D4" to
+ * a ptgArea3d.
+ *
+ * @access private
+ * @param string $token An Excel range in the Sheet1!A1:A2 format.
+ * @return mixed The packed ptgArea3d token on success, PEAR_Error on failure.
+ */
+ function _convertRange3d($token)
+ {
+ $class = 2; // as far as I know, this is magick.
+
+ // Split the ref at the ! symbol
+ list($ext_ref, $range) = explode('!', $token);
+
+ // Convert the external reference part (different for BIFF8)
+ if ($this->_BIFF_version == 0x0500) {
+ $ext_ref = $this->_packExtRef($ext_ref);
+ if (PEAR::isError($ext_ref)) {
+ return $ext_ref;
+ }
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $ext_ref = $this->_getRefIndex($ext_ref);
+ if (PEAR::isError($ext_ref)) {
+ return $ext_ref;
+ }
+ }
+
+ // Split the range into 2 cell refs
+ list($cell1, $cell2) = explode(':', $range);
+
+ // Convert the cell references
+ if (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/", $cell1)) {
+ $cell_array1 = $this->_cellToPackedRowcol($cell1);
+ if (PEAR::isError($cell_array1)) {
+ return $cell_array1;
+ }
+ list($row1, $col1) = $cell_array1;
+ $cell_array2 = $this->_cellToPackedRowcol($cell2);
+ if (PEAR::isError($cell_array2)) {
+ return $cell_array2;
+ }
+ list($row2, $col2) = $cell_array2;
+ } else { // It's a rows range (like 26:27)
+ $cells_array = $this->_rangeToPackedRange($cell1.':'.$cell2);
+ if (PEAR::isError($cells_array)) {
+ return $cells_array;
+ }
+ list($row1, $col1, $row2, $col2) = $cells_array;
+ }
+
+ // The ptg value depends on the class of the ptg.
+ if ($class == 0) {
+ $ptgArea = pack("C", $this->ptg['ptgArea3d']);
+ } elseif ($class == 1) {
+ $ptgArea = pack("C", $this->ptg['ptgArea3dV']);
+ } elseif ($class == 2) {
+ $ptgArea = pack("C", $this->ptg['ptgArea3dA']);
+ } else {
+ return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE);
+ }
+
+ return $ptgArea . $ext_ref . $row1 . $row2 . $col1. $col2;
+ }
+
+ /**
+ * Convert an Excel reference such as A1, $B2, C$3 or $D$4 to a ptgRefV.
+ *
+ * @access private
+ * @param string $cell An Excel cell reference
+ * @return string The cell in packed() format with the corresponding ptg
+ */
+ function _convertRef2d($cell)
+ {
+ $class = 2; // as far as I know, this is magick.
+
+ // Convert the cell reference
+ $cell_array = $this->_cellToPackedRowcol($cell);
+ if (PEAR::isError($cell_array)) {
+ return $cell_array;
+ }
+ list($row, $col) = $cell_array;
+
+ // The ptg value depends on the class of the ptg.
+ if ($class == 0) {
+ $ptgRef = pack("C", $this->ptg['ptgRef']);
+ } elseif ($class == 1) {
+ $ptgRef = pack("C", $this->ptg['ptgRefV']);
+ } elseif ($class == 2) {
+ $ptgRef = pack("C", $this->ptg['ptgRefA']);
+ } else {
+ // TODO: use real error codes
+ return $this->raiseError("Unknown class $class");
+ }
+ return $ptgRef.$row.$col;
+ }
+
+ /**
+ * Convert an Excel 3d reference such as "Sheet1!A1" or "Sheet1:Sheet2!A1" to a
+ * ptgRef3d.
+ *
+ * @access private
+ * @param string $cell An Excel cell reference
+ * @return mixed The packed ptgRef3d token on success, PEAR_Error on failure.
+ */
+ function _convertRef3d($cell)
+ {
+ $class = 2; // as far as I know, this is magick.
+
+ // Split the ref at the ! symbol
+ list($ext_ref, $cell) = explode('!', $cell);
+
+ // Convert the external reference part (different for BIFF8)
+ if ($this->_BIFF_version == 0x0500) {
+ $ext_ref = $this->_packExtRef($ext_ref);
+ if (PEAR::isError($ext_ref)) {
+ return $ext_ref;
+ }
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $ext_ref = $this->_getRefIndex($ext_ref);
+ if (PEAR::isError($ext_ref)) {
+ return $ext_ref;
+ }
+ }
+
+ // Convert the cell reference part
+ list($row, $col) = $this->_cellToPackedRowcol($cell);
+
+ // The ptg value depends on the class of the ptg.
+ if ($class == 0) {
+ $ptgRef = pack("C", $this->ptg['ptgRef3d']);
+ } elseif ($class == 1) {
+ $ptgRef = pack("C", $this->ptg['ptgRef3dV']);
+ } elseif ($class == 2) {
+ $ptgRef = pack("C", $this->ptg['ptgRef3dA']);
+ } else {
+ return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE);
+ }
+
+ return $ptgRef . $ext_ref. $row . $col;
+ }
+
+ /**
+ * Convert the sheet name part of an external reference, for example "Sheet1" or
+ * "Sheet1:Sheet2", to a packed structure.
+ *
+ * @access private
+ * @param string $ext_ref The name of the external reference
+ * @return string The reference index in packed() format
+ */
+ function _packExtRef($ext_ref)
+ {
+ $ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading ' if any.
+ $ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any.
+
+ // Check if there is a sheet range eg., Sheet1:Sheet2.
+ if (preg_match("/:/", $ext_ref)) {
+ list($sheet_name1, $sheet_name2) = explode(':', $ext_ref);
+
+ $sheet1 = $this->_getSheetIndex($sheet_name1);
+ if ($sheet1 == -1) {
+ return $this->raiseError("Unknown sheet name $sheet_name1 in formula");
+ }
+ $sheet2 = $this->_getSheetIndex($sheet_name2);
+ if ($sheet2 == -1) {
+ return $this->raiseError("Unknown sheet name $sheet_name2 in formula");
+ }
+
+ // Reverse max and min sheet numbers if necessary
+ if ($sheet1 > $sheet2) {
+ list($sheet1, $sheet2) = array($sheet2, $sheet1);
+ }
+ } else { // Single sheet name only.
+ $sheet1 = $this->_getSheetIndex($ext_ref);
+ if ($sheet1 == -1) {
+ return $this->raiseError("Unknown sheet name $ext_ref in formula");
+ }
+ $sheet2 = $sheet1;
+ }
+
+ // References are stored relative to 0xFFFF.
+ $offset = -1 - $sheet1;
+
+ return pack('vdvv', $offset, 0x00, $sheet1, $sheet2);
+ }
+
+ /**
+ * Look up the REF index that corresponds to an external sheet name
+ * (or range). If it doesn't exist yet add it to the workbook's references
+ * array. It assumes all sheet names given must exist.
+ *
+ * @access private
+ * @param string $ext_ref The name of the external reference
+ * @return mixed The reference index in packed() format on success,
+ * PEAR_Error on failure
+ */
+ function _getRefIndex($ext_ref)
+ {
+ $ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading ' if any.
+ $ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any.
+
+ // Check if there is a sheet range eg., Sheet1:Sheet2.
+ if (preg_match("/:/", $ext_ref)) {
+ list($sheet_name1, $sheet_name2) = explode(':', $ext_ref);
+
+ $sheet1 = $this->_getSheetIndex($sheet_name1);
+ if ($sheet1 == -1) {
+ return $this->raiseError("Unknown sheet name $sheet_name1 in formula");
+ }
+ $sheet2 = $this->_getSheetIndex($sheet_name2);
+ if ($sheet2 == -1) {
+ return $this->raiseError("Unknown sheet name $sheet_name2 in formula");
+ }
+
+ // Reverse max and min sheet numbers if necessary
+ if ($sheet1 > $sheet2) {
+ list($sheet1, $sheet2) = array($sheet2, $sheet1);
+ }
+ } else { // Single sheet name only.
+ $sheet1 = $this->_getSheetIndex($ext_ref);
+ if ($sheet1 == -1) {
+ return $this->raiseError("Unknown sheet name $ext_ref in formula");
+ }
+ $sheet2 = $sheet1;
+ }
+
+ // assume all references belong to this document
+ $supbook_index = 0x00;
+ $ref = pack('vvv', $supbook_index, $sheet1, $sheet2);
+ $total_references = count($this->_references);
+ $index = -1;
+ for ($i = 0; $i < $total_references; $i++) {
+ if ($ref == $this->_references[$i]) {
+ $index = $i;
+ break;
+ }
+ }
+ // if REF was not found add it to references array
+ if ($index == -1) {
+ $this->_references[$total_references] = $ref;
+ $index = $total_references;
+ }
+
+ return pack('v', $index);
+ }
+
+ /**
+ * Look up the index that corresponds to an external sheet name. The hash of
+ * sheet names is updated by the addworksheet() method of the
+ * Spreadsheet_Excel_Writer_Workbook class.
+ *
+ * @access private
+ * @return integer The sheet index, -1 if the sheet was not found
+ */
+ function _getSheetIndex($sheet_name)
+ {
+ if (!isset($this->_ext_sheets[$sheet_name])) {
+ return -1;
+ } else {
+ return $this->_ext_sheets[$sheet_name];
+ }
+ }
+
+ /**
+ * This method is used to update the array of sheet names. It is
+ * called by the addWorksheet() method of the
+ * Spreadsheet_Excel_Writer_Workbook class.
+ *
+ * @access public
+ * @see Spreadsheet_Excel_Writer_Workbook::addWorksheet()
+ * @param string $name The name of the worksheet being added
+ * @param integer $index The index of the worksheet being added
+ */
+ function setExtSheet($name, $index)
+ {
+ $this->_ext_sheets[$name] = $index;
+ }
+
+ /**
+ * pack() row and column into the required 3 or 4 byte format.
+ *
+ * @access private
+ * @param string $cell The Excel cell reference to be packed
+ * @return array Array containing the row and column in packed() format
+ */
+ function _cellToPackedRowcol($cell)
+ {
+ $cell = strtoupper($cell);
+ list($row, $col, $row_rel, $col_rel) = $this->_cellToRowcol($cell);
+ if ($col >= 256) {
+ return $this->raiseError("Column in: $cell greater than 255");
+ }
+ // FIXME: change for BIFF8
+ if ($row >= 16384) {
+ return $this->raiseError("Row in: $cell greater than 16384 ");
+ }
+
+ // Set the high bits to indicate if row or col are relative.
+ if ($this->_BIFF_version == 0x0500) {
+ $row |= $col_rel << 14;
+ $row |= $row_rel << 15;
+ $col = pack('C', $col);
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $col |= $col_rel << 14;
+ $col |= $row_rel << 15;
+ $col = pack('v', $col);
+ }
+ $row = pack('v', $row);
+
+ return array($row, $col);
+ }
+
+ /**
+ * pack() row range into the required 3 or 4 byte format.
+ * Just using maximum col/rows, which is probably not the correct solution
+ *
+ * @access private
+ * @param string $range The Excel range to be packed
+ * @return array Array containing (row1,col1,row2,col2) in packed() format
+ */
+ function _rangeToPackedRange($range)
+ {
+ preg_match('/(\$)?(\d+)\:(\$)?(\d+)/', $range, $match);
+ // return absolute rows if there is a $ in the ref
+ $row1_rel = empty($match[1]) ? 1 : 0;
+ $row1 = $match[2];
+ $row2_rel = empty($match[3]) ? 1 : 0;
+ $row2 = $match[4];
+ // Convert 1-index to zero-index
+ $row1--;
+ $row2--;
+ // Trick poor inocent Excel
+ $col1 = 0;
+ $col2 = 16383; // FIXME: maximum possible value for Excel 5 (change this!!!)
+
+ // FIXME: this changes for BIFF8
+ if (($row1 >= 16384) or ($row2 >= 16384)) {
+ return $this->raiseError("Row in: $range greater than 16384 ");
+ }
+
+ // Set the high bits to indicate if rows are relative.
+ if ($this->_BIFF_version == 0x0500) {
+ $row1 |= $row1_rel << 14; // FIXME: probably a bug
+ $row2 |= $row2_rel << 15;
+ $col1 = pack('C', $col1);
+ $col2 = pack('C', $col2);
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $col1 |= $row1_rel << 15;
+ $col2 |= $row2_rel << 15;
+ $col1 = pack('v', $col1);
+ $col2 = pack('v', $col2);
+ }
+ $row1 = pack('v', $row1);
+ $row2 = pack('v', $row2);
+
+ return array($row1, $col1, $row2, $col2);
+ }
+
+ /**
+ * Convert an Excel cell reference such as A1 or $B2 or C$3 or $D$4 to a zero
+ * indexed row and column number. Also returns two (0,1) values to indicate
+ * whether the row or column are relative references.
+ *
+ * @access private
+ * @param string $cell The Excel cell reference in A1 format.
+ * @return array
+ */
+ function _cellToRowcol($cell)
+ {
+ preg_match('/(\$)?([A-I]?[A-Z])(\$)?(\d+)/',$cell,$match);
+ // return absolute column if there is a $ in the ref
+ $col_rel = empty($match[1]) ? 1 : 0;
+ $col_ref = $match[2];
+ $row_rel = empty($match[3]) ? 1 : 0;
+ $row = $match[4];
+
+ // Convert base26 column string to a number.
+ $expn = strlen($col_ref) - 1;
+ $col = 0;
+ $col_ref_length = strlen($col_ref);
+ for ($i = 0; $i < $col_ref_length; $i++) {
+ $col += (ord($col_ref{$i}) - ord('A') + 1) * pow(26, $expn);
+ $expn--;
+ }
+
+ // Convert 1-index to zero-index
+ $row--;
+ $col--;
+
+ return array($row, $col, $row_rel, $col_rel);
+ }
+
+ /**
+ * Advance to the next valid token.
+ *
+ * @access private
+ */
+ function _advance()
+ {
+ $i = $this->_current_char;
+ $formula_length = strlen($this->_formula);
+ // eat up white spaces
+ if ($i < $formula_length) {
+ while ($this->_formula{$i} == " ") {
+ $i++;
+ }
+
+ if ($i < ($formula_length - 1)) {
+ $this->_lookahead = $this->_formula{$i+1};
+ }
+ $token = '';
+ }
+
+ while ($i < $formula_length) {
+ $token .= $this->_formula{$i};
+ if ($i < ($formula_length - 1)) {
+ $this->_lookahead = $this->_formula{$i+1};
+ } else {
+ $this->_lookahead = '';
+ }
+
+ if ($this->_match($token) != '') {
+ //if ($i < strlen($this->_formula) - 1) {
+ // $this->_lookahead = $this->_formula{$i+1};
+ //}
+ $this->_current_char = $i + 1;
+ $this->_current_token = $token;
+ return 1;
+ }
+
+ if ($i < ($formula_length - 2)) {
+ $this->_lookahead = $this->_formula{$i+2};
+ } else { // if we run out of characters _lookahead becomes empty
+ $this->_lookahead = '';
+ }
+ $i++;
+ }
+ //die("Lexical error ".$this->_current_char);
+ }
+
+ /**
+ * Checks if it's a valid token.
+ *
+ * @access private
+ * @param mixed $token The token to check.
+ * @return mixed The checked token or false on failure
+ */
+ function _match($token)
+ {
+ switch($token) {
+ case SPREADSHEET_EXCEL_WRITER_ADD:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_SUB:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_MUL:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_DIV:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_OPEN:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_CLOSE:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_COMA:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_SEMICOLON:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_GT:
+ if ($this->_lookahead == '=') { // it's a GE token
+ break;
+ }
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_LT:
+ // it's a LE or a NE token
+ if (($this->_lookahead == '=') or ($this->_lookahead == '>')) {
+ break;
+ }
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_GE:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_LE:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_EQ:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_NE:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_CONCAT:
+ return $token;
+ break;
+ default:
+ // if it's a reference
+ if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$token) and
+ !preg_match("/[0-9]/",$this->_lookahead) and
+ ($this->_lookahead != ':') and ($this->_lookahead != '.') and
+ ($this->_lookahead != '!'))
+ {
+ return $token;
+ }
+ // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1)
+ elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z][0-9]+$/u",$token) and
+ !preg_match("/[0-9]/",$this->_lookahead) and
+ ($this->_lookahead != ':') and ($this->_lookahead != '.'))
+ {
+ return $token;
+ }
+ // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1)
+ elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z][0-9]+$/u",$token) and
+ !preg_match("/[0-9]/",$this->_lookahead) and
+ ($this->_lookahead != ':') and ($this->_lookahead != '.'))
+ {
+ return $token;
+ }
+ // if it's a range (A1:A2)
+ elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and
+ !preg_match("/[0-9]/",$this->_lookahead))
+ {
+ return $token;
+ }
+ // if it's a range (A1..A2)
+ elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and
+ !preg_match("/[0-9]/",$this->_lookahead))
+ {
+ return $token;
+ }
+ // If it's an external range like Sheet1!A1 or Sheet1:Sheet2!A1:B2
+ elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$token) and
+ !preg_match("/[0-9]/",$this->_lookahead))
+ {
+ return $token;
+ }
+ // If it's an external range like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1:B2
+ elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$token) and
+ !preg_match("/[0-9]/",$this->_lookahead))
+ {
+ return $token;
+ }
+ // If it's a number (check that it's not a sheet name or range)
+ elseif (is_numeric($token) and
+ (!is_numeric($token.$this->_lookahead) or ($this->_lookahead == '')) and
+ ($this->_lookahead != '!') and ($this->_lookahead != ':'))
+ {
+ return $token;
+ }
+ // If it's a string (of maximum 255 characters)
+ elseif (preg_match("/^\"[^\"]{0,255}\"$/",$token))
+ {
+ return $token;
+ }
+ // if it's a function call
+ elseif (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/i",$token) and ($this->_lookahead == "("))
+ {
+ return $token;
+ }
+ return '';
+ }
+ }
+
+ /**
+ * The parsing method. It parses a formula.
+ *
+ * @access public
+ * @param string $formula The formula to parse, without the initial equal
+ * sign (=).
+ * @return mixed true on success, PEAR_Error on failure
+ */
+ function parse($formula)
+ {
+ $this->_current_char = 0;
+ $this->_formula = $formula;
+ $this->_lookahead = $formula{1};
+ $this->_advance();
+ $this->_parse_tree = $this->_condition();
+ if (PEAR::isError($this->_parse_tree)) {
+ return $this->_parse_tree;
+ }
+ return true;
+ }
+
+ /**
+ * It parses a condition. It assumes the following rule:
+ * Cond -> Expr [(">" | "<") Expr]
+ *
+ * @access private
+ * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure
+ */
+ function _condition()
+ {
+ $result = $this->_expression();
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LT) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgLT', $result, $result2);
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GT) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgGT', $result, $result2);
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LE) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgLE', $result, $result2);
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GE) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgGE', $result, $result2);
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_EQ) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgEQ', $result, $result2);
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_NE) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgNE', $result, $result2);
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_CONCAT) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgConcat', $result, $result2);
+ }
+ return $result;
+ }
+
+ /**
+ * It parses a expression. It assumes the following rule:
+ * Expr -> Term [("+" | "-") Term]
+ * -> "string"
+ * -> "-" Term
+ *
+ * @access private
+ * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure
+ */
+ function _expression()
+ {
+ // If it's a string return a string node
+ if (preg_match("/^\"[^\"]{0,255}\"$/", $this->_current_token)) {
+ $result = $this->_createTree($this->_current_token, '', '');
+ $this->_advance();
+ return $result;
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_SUB) {
+ // catch "-" Term
+ $this->_advance();
+ $result2 = $this->_expression();
+ $result = $this->_createTree('ptgUminus', $result2, '');
+ return $result;
+ }
+ $result = $this->_term();
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) or
+ ($this->_current_token == SPREADSHEET_EXCEL_WRITER_SUB)) {
+ /**/
+ if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) {
+ $this->_advance();
+ $result2 = $this->_term();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgAdd', $result, $result2);
+ } else {
+ $this->_advance();
+ $result2 = $this->_term();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgSub', $result, $result2);
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * This function just introduces a ptgParen element in the tree, so that Excel
+ * doesn't get confused when working with a parenthesized formula afterwards.
+ *
+ * @access private
+ * @see _fact()
+ * @return array The parsed ptg'd tree
+ */
+ function _parenthesizedExpression()
+ {
+ $result = $this->_createTree('ptgParen', $this->_expression(), '');
+ return $result;
+ }
+
+ /**
+ * It parses a term. It assumes the following rule:
+ * Term -> Fact [("*" | "/") Fact]
+ *
+ * @access private
+ * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure
+ */
+ function _term()
+ {
+ $result = $this->_fact();
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) or
+ ($this->_current_token == SPREADSHEET_EXCEL_WRITER_DIV)) {
+ /**/
+ if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) {
+ $this->_advance();
+ $result2 = $this->_fact();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgMul', $result, $result2);
+ } else {
+ $this->_advance();
+ $result2 = $this->_fact();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgDiv', $result, $result2);
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * It parses a factor. It assumes the following rule:
+ * Fact -> ( Expr )
+ * | CellRef
+ * | CellRange
+ * | Number
+ * | Function
+ *
+ * @access private
+ * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure
+ */
+ function _fact()
+ {
+ if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_OPEN) {
+ $this->_advance(); // eat the "("
+ $result = $this->_parenthesizedExpression();
+ if ($this->_current_token != SPREADSHEET_EXCEL_WRITER_CLOSE) {
+ return $this->raiseError("')' token expected.");
+ }
+ $this->_advance(); // eat the ")"
+ return $result;
+ }
+ // if it's a reference
+ if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$this->_current_token))
+ {
+ $result = $this->_createTree($this->_current_token, '', '');
+ $this->_advance();
+ return $result;
+ }
+ // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1)
+ elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z][0-9]+$/u",$this->_current_token))
+ {
+ $result = $this->_createTree($this->_current_token, '', '');
+ $this->_advance();
+ return $result;
+ }
+ // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1)
+ elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z][0-9]+$/u",$this->_current_token))
+ {
+ $result = $this->_createTree($this->_current_token, '', '');
+ $this->_advance();
+ return $result;
+ }
+ // if it's a range
+ elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$this->_current_token) or
+ preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$this->_current_token))
+ {
+ $result = $this->_current_token;
+ $this->_advance();
+ return $result;
+ }
+ // If it's an external range (Sheet1!A1 or Sheet1!A1:B2)
+ elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$this->_current_token))
+ {
+ $result = $this->_current_token;
+ $this->_advance();
+ return $result;
+ }
+ // If it's an external range ('Sheet1'!A1 or 'Sheet1'!A1:B2)
+ elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$this->_current_token))
+ {
+ $result = $this->_current_token;
+ $this->_advance();
+ return $result;
+ }
+ elseif (is_numeric($this->_current_token))
+ {
+ $result = $this->_createTree($this->_current_token, '', '');
+ $this->_advance();
+ return $result;
+ }
+ // if it's a function call
+ elseif (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/i",$this->_current_token))
+ {
+ $result = $this->_func();
+ return $result;
+ }
+ return $this->raiseError("Syntax error: ".$this->_current_token.
+ ", lookahead: ".$this->_lookahead.
+ ", current char: ".$this->_current_char);
+ }
+
+ /**
+ * It parses a function call. It assumes the following rule:
+ * Func -> ( Expr [,Expr]* )
+ *
+ * @access private
+ * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure
+ */
+ function _func()
+ {
+ $num_args = 0; // number of arguments received
+ $function = strtoupper($this->_current_token);
+ $result = ''; // initialize result
+ $this->_advance();
+ $this->_advance(); // eat the "("
+ while ($this->_current_token != ')') {
+ /**/
+ if ($num_args > 0) {
+ if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_COMA or
+ $this->_current_token == SPREADSHEET_EXCEL_WRITER_SEMICOLON)
+ {
+ $this->_advance(); // eat the "," or ";"
+ } else {
+ return $this->raiseError("Syntax error: comma expected in ".
+ "function $function, arg #{$num_args}");
+ }
+ $result2 = $this->_condition();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('arg', $result, $result2);
+ } else { // first argument
+ $result2 = $this->_condition();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('arg', '', $result2);
+ }
+ $num_args++;
+ }
+ if (!isset($this->_functions[$function])) {
+ return $this->raiseError("Function $function() doesn't exist");
+ }
+ $args = $this->_functions[$function][1];
+ // If fixed number of args eg. TIME($i,$j,$k). Check that the number of args is valid.
+ if (($args >= 0) and ($args != $num_args)) {
+ return $this->raiseError("Incorrect number of arguments in function $function() ");
+ }
+
+ $result = $this->_createTree($function, $result, $num_args);
+ $this->_advance(); // eat the ")"
+ return $result;
+ }
+
+ /**
+ * Creates a tree. In fact an array which may have one or two arrays (sub-trees)
+ * as elements.
+ *
+ * @access private
+ * @param mixed $value The value of this node.
+ * @param mixed $left The left array (sub-tree) or a final node.
+ * @param mixed $right The right array (sub-tree) or a final node.
+ * @return array A tree
+ */
+ function _createTree($value, $left, $right)
+ {
+ return array('value' => $value, 'left' => $left, 'right' => $right);
+ }
+
+ /**
+ * Builds a string containing the tree in reverse polish notation (What you
+ * would use in a HP calculator stack).
+ * The following tree:
+ *
+ * +
+ * / \
+ * 2 3
+ *
+ * produces: "23+"
+ *
+ * The following tree:
+ *
+ * +
+ * / \
+ * 3 *
+ * / \
+ * 6 A1
+ *
+ * produces: "36A1*+"
+ *
+ * In fact all operands, functions, references, etc... are written as ptg's
+ *
+ * @access public
+ * @param array $tree The optional tree to convert.
+ * @return string The tree in reverse polish notation
+ */
+ function toReversePolish($tree = array())
+ {
+ $polish = ""; // the string we are going to return
+ if (empty($tree)) { // If it's the first call use _parse_tree
+ $tree = $this->_parse_tree;
+ }
+ if (is_array($tree['left'])) {
+ $converted_tree = $this->toReversePolish($tree['left']);
+ if (PEAR::isError($converted_tree)) {
+ return $converted_tree;
+ }
+ $polish .= $converted_tree;
+ } elseif ($tree['left'] != '') { // It's a final node
+ $converted_tree = $this->_convert($tree['left']);
+ if (PEAR::isError($converted_tree)) {
+ return $converted_tree;
+ }
+ $polish .= $converted_tree;
+ }
+ if (is_array($tree['right'])) {
+ $converted_tree = $this->toReversePolish($tree['right']);
+ if (PEAR::isError($converted_tree)) {
+ return $converted_tree;
+ }
+ $polish .= $converted_tree;
+ } elseif ($tree['right'] != '') { // It's a final node
+ $converted_tree = $this->_convert($tree['right']);
+ if (PEAR::isError($converted_tree)) {
+ return $converted_tree;
+ }
+ $polish .= $converted_tree;
+ }
+ // if it's a function convert it here (so we can set it's arguments)
+ if (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/",$tree['value']) and
+ !preg_match('/^([A-Ia-i]?[A-Za-z])(\d+)$/',$tree['value']) and
+ !preg_match("/^[A-Ia-i]?[A-Za-z](\d+)\.\.[A-Ia-i]?[A-Za-z](\d+)$/",$tree['value']) and
+ !is_numeric($tree['value']) and
+ !isset($this->ptg[$tree['value']]))
+ {
+ // left subtree for a function is always an array.
+ if ($tree['left'] != '') {
+ $left_tree = $this->toReversePolish($tree['left']);
+ } else {
+ $left_tree = '';
+ }
+ if (PEAR::isError($left_tree)) {
+ return $left_tree;
+ }
+ // add it's left subtree and return.
+ return $left_tree.$this->_convertFunction($tree['value'], $tree['right']);
+ } else {
+ $converted_tree = $this->_convert($tree['value']);
+ if (PEAR::isError($converted_tree)) {
+ return $converted_tree;
+ }
+ }
+ $polish .= $converted_tree;
+ return $polish;
+ }
+}
+?>
diff --git a/vendor/library/Excel/Writer/Validator.php b/vendor/library/Excel/Writer/Validator.php
new file mode 100644
index 0000000..0f091c6
--- /dev/null
+++ b/vendor/library/Excel/Writer/Validator.php
@@ -0,0 +1,230 @@
+
+*
+* License Information:
+*
+* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
+* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+//require_once('PEAR.php');
+
+// Possible operator types
+
+/*
+FIXME: change prefixes
+*/
+define("OP_BETWEEN", 0x00);
+define("OP_NOTBETWEEN", 0x01);
+define("OP_EQUAL", 0x02);
+define("OP_NOTEQUAL", 0x03);
+define("OP_GT", 0x04);
+define("OP_LT", 0x05);
+define("OP_GTE", 0x06);
+define("OP_LTE", 0x07);
+
+/**
+* Baseclass for generating Excel DV records (validations)
+*
+* @author Herman Kuiper
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+class Spreadsheet_Excel_Writer_Validator
+{
+ var $_type;
+ var $_style;
+ var $_fixedList;
+ var $_blank;
+ var $_incell;
+ var $_showprompt;
+ var $_showerror;
+ var $_title_prompt;
+ var $_descr_prompt;
+ var $_title_error;
+ var $_descr_error;
+ var $_operator;
+ var $_formula1;
+ var $_formula2;
+ /**
+ * The parser from the workbook. Used to parse validation formulas also
+ * @var Spreadsheet_Excel_Writer_Parser
+ */
+ var $_parser;
+
+ function Spreadsheet_Excel_Writer_Validator(&$parser)
+ {
+ $this->_parser = $parser;
+ $this->_type = 0x01; // FIXME: add method for setting datatype
+ $this->_style = 0x00;
+ $this->_fixedList = false;
+ $this->_blank = false;
+ $this->_incell = false;
+ $this->_showprompt = false;
+ $this->_showerror = true;
+ $this->_title_prompt = "\x00";
+ $this->_descr_prompt = "\x00";
+ $this->_title_error = "\x00";
+ $this->_descr_error = "\x00";
+ $this->_operator = 0x00; // default is equal
+ $this->_formula1 = '';
+ $this->_formula2 = '';
+ }
+
+ function setPrompt($promptTitle = "\x00", $promptDescription = "\x00", $showPrompt = true)
+ {
+ $this->_showprompt = $showPrompt;
+ $this->_title_prompt = $promptTitle;
+ $this->_descr_prompt = $promptDescription;
+ }
+
+ function setError($errorTitle = "\x00", $errorDescription = "\x00", $showError = true)
+ {
+ $this->_showerror = $showError;
+ $this->_title_error = $errorTitle;
+ $this->_descr_error = $errorDescription;
+ }
+
+ function allowBlank()
+ {
+ $this->_blank = true;
+ }
+
+ function onInvalidStop()
+ {
+ $this->_style = 0x00;
+ }
+
+ function onInvalidWarn()
+ {
+ $this->_style = 0x01;
+ }
+
+ function onInvalidInfo()
+ {
+ $this->_style = 0x02;
+ }
+
+ function setFormula1($formula)
+ {
+ // Parse the formula using the parser in Parser.php
+ $error = $this->_parser->parse($formula);
+ if (PEAR::isError($error)) {
+ return $this->_formula1;
+ }
+
+ $this->_formula1 = $this->_parser->toReversePolish();
+ if (PEAR::isError($this->_formula1)) {
+ return $this->_formula1;
+ }
+ return true;
+ }
+
+ function setFormula2($formula)
+ {
+ // Parse the formula using the parser in Parser.php
+ $error = $this->_parser->parse($formula);
+ if (PEAR::isError($error)) {
+ return $this->_formula2;
+ }
+
+ $this->_formula2 = $this->_parser->toReversePolish();
+ if (PEAR::isError($this->_formula2)) {
+ return $this->_formula2;
+ }
+ return true;
+ }
+
+ function _getOptions()
+ {
+ $options = $this->_type;
+ $options |= $this->_style << 3;
+ if ($this->_fixedList) {
+ $options |= 0x80;
+ }
+ if ($this->_blank) {
+ $options |= 0x100;
+ }
+ if (!$this->_incell) {
+ $options |= 0x200;
+ }
+ if ($this->_showprompt) {
+ $options |= 0x40000;
+ }
+ if ($this->_showerror) {
+ $options |= 0x80000;
+ }
+ $options |= $this->_operator << 20;
+
+ return $options;
+ }
+
+ function _getData()
+ {
+ $title_prompt_len = strlen($this->_title_prompt);
+ $descr_prompt_len = strlen($this->_descr_prompt);
+ $title_error_len = strlen($this->_title_error);
+ $descr_error_len = strlen($this->_descr_error);
+
+ $formula1_size = strlen($this->_formula1);
+ $formula2_size = strlen($this->_formula2);
+
+ $data = pack("V", $this->_getOptions());
+ $data .= pack("vC", $title_prompt_len, 0x00) . $this->_title_prompt;
+ $data .= pack("vC", $title_error_len, 0x00) . $this->_title_error;
+ $data .= pack("vC", $descr_prompt_len, 0x00) . $this->_descr_prompt;
+ $data .= pack("vC", $descr_error_len, 0x00) . $this->_descr_error;
+
+ $data .= pack("vv", $formula1_size, 0x0000) . $this->_formula1;
+ $data .= pack("vv", $formula2_size, 0x0000) . $this->_formula2;
+
+ return $data;
+ }
+}
+
+/*class Spreadsheet_Excel_Writer_Validation_List extends Spreadsheet_Excel_Writer_Validation
+{
+ function Spreadsheet_Excel_Writer_Validation_list()
+ {
+ parent::Spreadsheet_Excel_Writer_Validation();
+ $this->_type = 0x03;
+ }
+
+ function setList($source, $incell = true)
+ {
+ $this->_incell = $incell;
+ $this->_fixedList = true;
+
+ $source = implode("\x00", $source);
+ $this->_formula1 = pack("CCC", 0x17, strlen($source), 0x0c) . $source;
+ }
+
+ function setRow($row, $col1, $col2, $incell = true)
+ {
+ $this->_incell = $incell;
+ //$this->_formula1 = ...;
+ }
+
+ function setCol($col, $row1, $row2, $incell = true)
+ {
+ $this->_incell = $incell;
+ //$this->_formula1 = ...;
+ }
+}*/
+
+?>
diff --git a/vendor/library/Excel/Writer/Workbook.php b/vendor/library/Excel/Writer/Workbook.php
new file mode 100644
index 0000000..7b710e0
--- /dev/null
+++ b/vendor/library/Excel/Writer/Workbook.php
@@ -0,0 +1,1611 @@
+
+*
+* The majority of this is _NOT_ my code. I simply ported it from the
+* PERL Spreadsheet::WriteExcel module.
+*
+* The author of the Spreadsheet::WriteExcel module is John McNamara
+*
+*
+* I _DO_ maintain this code, and John McNamara has nothing to do with the
+* porting of this code to PHP. Any questions directly related to this
+* class library should be directed to me.
+*
+* License Information:
+*
+* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
+* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+require_once 'Spreadsheet/Excel/Writer/Format.php';
+require_once 'Spreadsheet/Excel/Writer/BIFFwriter.php';
+require_once 'Spreadsheet/Excel/Writer/Worksheet.php';
+require_once 'Spreadsheet/Excel/Writer/Parser.php';
+require_once 'OLE/PPS/Root.php';
+require_once 'OLE/PPS/File.php';
+
+/**
+* Class for generating Excel Spreadsheets
+*
+* @author Xavier Noguer
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+
+class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwriter
+{
+ /**
+ * Filename for the Workbook
+ * @var string
+ */
+ var $_filename;
+
+ /**
+ * Formula parser
+ * @var object Parser
+ */
+ var $_parser;
+
+ /**
+ * Flag for 1904 date system (0 => base date is 1900, 1 => base date is 1904)
+ * @var integer
+ */
+ var $_1904;
+
+ /**
+ * The active worksheet of the workbook (0 indexed)
+ * @var integer
+ */
+ var $_activesheet;
+
+ /**
+ * 1st displayed worksheet in the workbook (0 indexed)
+ * @var integer
+ */
+ var $_firstsheet;
+
+ /**
+ * Number of workbook tabs selected
+ * @var integer
+ */
+ var $_selected;
+
+ /**
+ * Index for creating adding new formats to the workbook
+ * @var integer
+ */
+ var $_xf_index;
+
+ /**
+ * Flag for preventing close from being called twice.
+ * @var integer
+ * @see close()
+ */
+ var $_fileclosed;
+
+ /**
+ * The BIFF file size for the workbook.
+ * @var integer
+ * @see _calcSheetOffsets()
+ */
+ var $_biffsize;
+
+ /**
+ * The default sheetname for all sheets created.
+ * @var string
+ */
+ var $_sheetname;
+
+ /**
+ * The default XF format.
+ * @var object Format
+ */
+ var $_tmp_format;
+
+ /**
+ * Array containing references to all of this workbook's worksheets
+ * @var array
+ */
+ var $_worksheets;
+
+ /**
+ * Array of sheetnames for creating the EXTERNSHEET records
+ * @var array
+ */
+ var $_sheetnames;
+
+ /**
+ * Array containing references to all of this workbook's formats
+ * @var array
+ */
+ var $_formats;
+
+ /**
+ * Array containing the colour palette
+ * @var array
+ */
+ var $_palette;
+
+ /**
+ * The default format for URLs.
+ * @var object Format
+ */
+ var $_url_format;
+
+ /**
+ * The codepage indicates the text encoding used for strings
+ * @var integer
+ */
+ var $_codepage;
+
+ /**
+ * The country code used for localization
+ * @var integer
+ */
+ var $_country_code;
+
+ /**
+ * number of bytes for sizeinfo of strings
+ * @var integer
+ */
+ var $_string_sizeinfo_size;
+
+ /**
+ * Class constructor
+ *
+ * @param string filename for storing the workbook. "-" for writing to stdout.
+ * @access public
+ */
+ function Spreadsheet_Excel_Writer_Workbook($filename)
+ {
+ // It needs to call its parent's constructor explicitly
+ $this->Spreadsheet_Excel_Writer_BIFFwriter();
+
+ $this->_filename = $filename;
+ $this->_parser = new Spreadsheet_Excel_Writer_Parser($this->_byte_order, $this->_BIFF_version);
+ $this->_1904 = 0;
+ $this->_activesheet = 0;
+ $this->_firstsheet = 0;
+ $this->_selected = 0;
+ $this->_xf_index = 16; // 15 style XF's and 1 cell XF.
+ $this->_fileclosed = 0;
+ $this->_biffsize = 0;
+ $this->_sheetname = 'Sheet';
+ $this->_tmp_format = new Spreadsheet_Excel_Writer_Format($this->_BIFF_version);
+ $this->_worksheets = array();
+ $this->_sheetnames = array();
+ $this->_formats = array();
+ $this->_palette = array();
+ $this->_codepage = 0x04E4; // FIXME: should change for BIFF8
+ $this->_country_code = -1;
+ $this->_string_sizeinfo = 3;
+
+ // Add the default format for hyperlinks
+ $this->_url_format =& $this->addFormat(array('color' => 'blue', 'underline' => 1));
+ $this->_str_total = 0;
+ $this->_str_unique = 0;
+ $this->_str_table = array();
+ $this->_setPaletteXl97();
+ }
+
+ /**
+ * Calls finalization methods.
+ * This method should always be the last one to be called on every workbook
+ *
+ * @access public
+ * @return mixed true on success. PEAR_Error on failure
+ */
+ function close()
+ {
+ if ($this->_fileclosed) { // Prevent close() from being called twice.
+ return true;
+ }
+ $res = $this->_storeWorkbook();
+ if ($this->isError($res)) {
+ return $this->raiseError($res->getMessage());
+ }
+ $this->_fileclosed = 1;
+ return true;
+ }
+
+ /**
+ * An accessor for the _worksheets[] array
+ * Returns an array of the worksheet objects in a workbook
+ * It actually calls to worksheets()
+ *
+ * @access public
+ * @see worksheets()
+ * @return array
+ */
+ function sheets()
+ {
+ return $this->worksheets();
+ }
+
+ /**
+ * An accessor for the _worksheets[] array.
+ * Returns an array of the worksheet objects in a workbook
+ *
+ * @access public
+ * @return array
+ */
+ function worksheets()
+ {
+ return $this->_worksheets;
+ }
+
+ /**
+ * Sets the BIFF version.
+ * This method exists just to access experimental functionality
+ * from BIFF8. It will be deprecated !
+ * Only possible value is 8 (Excel 97/2000).
+ * For any other value it fails silently.
+ *
+ * @access public
+ * @param integer $version The BIFF version
+ */
+ function setVersion($version)
+ {
+ if ($version == 8) { // only accept version 8
+ $version = 0x0600;
+ $this->_BIFF_version = $version;
+ // change BIFFwriter limit for CONTINUE records
+ $this->_limit = 8228;
+ $this->_tmp_format->_BIFF_version = $version;
+ $this->_url_format->_BIFF_version = $version;
+ $this->_parser->_BIFF_version = $version;
+ $this->_codepage = 0x04B0;
+
+ $total_worksheets = count($this->_worksheets);
+ // change version for all worksheets too
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ $this->_worksheets[$i]->_BIFF_version = $version;
+ }
+
+ $total_formats = count($this->_formats);
+ // change version for all formats too
+ for ($i = 0; $i < $total_formats; $i++) {
+ $this->_formats[$i]->_BIFF_version = $version;
+ }
+ }
+ }
+
+ /**
+ * Set the country identifier for the workbook
+ *
+ * @access public
+ * @param integer $code Is the international calling country code for the
+ * chosen country.
+ */
+ function setCountry($code)
+ {
+ $this->_country_code = $code;
+ }
+
+ /**
+ * Add a new worksheet to the Excel workbook.
+ * If no name is given the name of the worksheet will be Sheeti$i, with
+ * $i in [1..].
+ *
+ * @access public
+ * @param string $name the optional name of the worksheet
+ * @return mixed reference to a worksheet object on success, PEAR_Error
+ * on failure
+ */
+ function &addWorksheet($name = '')
+ {
+ $index = count($this->_worksheets);
+ $sheetname = $this->_sheetname;
+
+ if ($name == '') {
+ $name = $sheetname.($index+1);
+ }
+
+ // Check that sheetname is <= 31 chars (Excel limit before BIFF8).
+ if ($this->_BIFF_version != 0x0600)
+ {
+ if (strlen($name) > 31) {
+ return $this->raiseError("Sheetname $name must be <= 31 chars");
+ }
+ } else {
+ if(function_exists('iconv')) {
+ $name = iconv('UTF-8','UTF-16LE',$name);
+ }
+ }
+
+ // Check that the worksheet name doesn't already exist: a fatal Excel error.
+ $total_worksheets = count($this->_worksheets);
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ if ($this->_worksheets[$i]->getName() == $name) {
+ return $this->raiseError("Worksheet '$name' already exists");
+ }
+ }
+
+ $worksheet = new Spreadsheet_Excel_Writer_Worksheet($this->_BIFF_version,
+ $name, $index,
+ $this->_activesheet, $this->_firstsheet,
+ $this->_str_total, $this->_str_unique,
+ $this->_str_table, $this->_url_format,
+ $this->_parser, $this->_tmp_dir);
+
+ $this->_worksheets[$index] = &$worksheet; // Store ref for iterator
+ $this->_sheetnames[$index] = $name; // Store EXTERNSHEET names
+ $this->_parser->setExtSheet($name, $index); // Register worksheet name with parser
+ return $worksheet;
+ }
+
+ /**
+ * Add a new format to the Excel workbook.
+ * Also, pass any properties to the Format constructor.
+ *
+ * @access public
+ * @param array $properties array with properties for initializing the format.
+ * @return &Spreadsheet_Excel_Writer_Format reference to an Excel Format
+ */
+ function &addFormat($properties = array())
+ {
+ $format = new Spreadsheet_Excel_Writer_Format($this->_BIFF_version, $this->_xf_index, $properties);
+ $this->_xf_index += 1;
+ $this->_formats[] = &$format;
+ return $format;
+ }
+
+ /**
+ * Create new validator.
+ *
+ * @access public
+ * @return &Spreadsheet_Excel_Writer_Validator reference to a Validator
+ */
+ function &addValidator()
+ {
+ include_once 'Spreadsheet/Excel/Writer/Validator.php';
+ /* FIXME: check for successful inclusion*/
+ $valid = new Spreadsheet_Excel_Writer_Validator($this->_parser);
+ return $valid;
+ }
+
+ /**
+ * Change the RGB components of the elements in the colour palette.
+ *
+ * @access public
+ * @param integer $index colour index
+ * @param integer $red red RGB value [0-255]
+ * @param integer $green green RGB value [0-255]
+ * @param integer $blue blue RGB value [0-255]
+ * @return integer The palette index for the custom color
+ */
+ function setCustomColor($index, $red, $green, $blue)
+ {
+ // Match a HTML #xxyyzz style parameter
+ /*if (defined $_[1] and $_[1] =~ /^#(\w\w)(\w\w)(\w\w)/ ) {
+ @_ = ($_[0], hex $1, hex $2, hex $3);
+ }*/
+
+ // Check that the colour index is the right range
+ if ($index < 8 or $index > 64) {
+ // TODO: assign real error codes
+ return $this->raiseError("Color index $index outside range: 8 <= index <= 64");
+ }
+
+ // Check that the colour components are in the right range
+ if (($red < 0 or $red > 255) ||
+ ($green < 0 or $green > 255) ||
+ ($blue < 0 or $blue > 255))
+ {
+ return $this->raiseError("Color component outside range: 0 <= color <= 255");
+ }
+
+ $index -= 8; // Adjust colour index (wingless dragonfly)
+
+ // Set the RGB value
+ $this->_palette[$index] = array($red, $green, $blue, 0);
+ return($index + 8);
+ }
+
+ /**
+ * Sets the colour palette to the Excel 97+ default.
+ *
+ * @access private
+ */
+ function _setPaletteXl97()
+ {
+ $this->_palette = array(
+ array(0x00, 0x00, 0x00, 0x00), // 8
+ array(0xff, 0xff, 0xff, 0x00), // 9
+ array(0xff, 0x00, 0x00, 0x00), // 10
+ array(0x00, 0xff, 0x00, 0x00), // 11
+ array(0x00, 0x00, 0xff, 0x00), // 12
+ array(0xff, 0xff, 0x00, 0x00), // 13
+ array(0xff, 0x00, 0xff, 0x00), // 14
+ array(0x00, 0xff, 0xff, 0x00), // 15
+ array(0x80, 0x00, 0x00, 0x00), // 16
+ array(0x00, 0x80, 0x00, 0x00), // 17
+ array(0x00, 0x00, 0x80, 0x00), // 18
+ array(0x80, 0x80, 0x00, 0x00), // 19
+ array(0x80, 0x00, 0x80, 0x00), // 20
+ array(0x00, 0x80, 0x80, 0x00), // 21
+ array(0xc0, 0xc0, 0xc0, 0x00), // 22
+ array(0x80, 0x80, 0x80, 0x00), // 23
+ array(0x99, 0x99, 0xff, 0x00), // 24
+ array(0x99, 0x33, 0x66, 0x00), // 25
+ array(0xff, 0xff, 0xcc, 0x00), // 26
+ array(0xcc, 0xff, 0xff, 0x00), // 27
+ array(0x66, 0x00, 0x66, 0x00), // 28
+ array(0xff, 0x80, 0x80, 0x00), // 29
+ array(0x00, 0x66, 0xcc, 0x00), // 30
+ array(0xcc, 0xcc, 0xff, 0x00), // 31
+ array(0x00, 0x00, 0x80, 0x00), // 32
+ array(0xff, 0x00, 0xff, 0x00), // 33
+ array(0xff, 0xff, 0x00, 0x00), // 34
+ array(0x00, 0xff, 0xff, 0x00), // 35
+ array(0x80, 0x00, 0x80, 0x00), // 36
+ array(0x80, 0x00, 0x00, 0x00), // 37
+ array(0x00, 0x80, 0x80, 0x00), // 38
+ array(0x00, 0x00, 0xff, 0x00), // 39
+ array(0x00, 0xcc, 0xff, 0x00), // 40
+ array(0xcc, 0xff, 0xff, 0x00), // 41
+ array(0xcc, 0xff, 0xcc, 0x00), // 42
+ array(0xff, 0xff, 0x99, 0x00), // 43
+ array(0x99, 0xcc, 0xff, 0x00), // 44
+ array(0xff, 0x99, 0xcc, 0x00), // 45
+ array(0xcc, 0x99, 0xff, 0x00), // 46
+ array(0xff, 0xcc, 0x99, 0x00), // 47
+ array(0x33, 0x66, 0xff, 0x00), // 48
+ array(0x33, 0xcc, 0xcc, 0x00), // 49
+ array(0x99, 0xcc, 0x00, 0x00), // 50
+ array(0xff, 0xcc, 0x00, 0x00), // 51
+ array(0xff, 0x99, 0x00, 0x00), // 52
+ array(0xff, 0x66, 0x00, 0x00), // 53
+ array(0x66, 0x66, 0x99, 0x00), // 54
+ array(0x96, 0x96, 0x96, 0x00), // 55
+ array(0x00, 0x33, 0x66, 0x00), // 56
+ array(0x33, 0x99, 0x66, 0x00), // 57
+ array(0x00, 0x33, 0x00, 0x00), // 58
+ array(0x33, 0x33, 0x00, 0x00), // 59
+ array(0x99, 0x33, 0x00, 0x00), // 60
+ array(0x99, 0x33, 0x66, 0x00), // 61
+ array(0x33, 0x33, 0x99, 0x00), // 62
+ array(0x33, 0x33, 0x33, 0x00), // 63
+ );
+ }
+
+ /**
+ * Assemble worksheets into a workbook and send the BIFF data to an OLE
+ * storage.
+ *
+ * @access private
+ * @return mixed true on success. PEAR_Error on failure
+ */
+ function _storeWorkbook()
+ {
+ if (count($this->_worksheets) == 0) {
+ return true;
+ }
+
+ // Ensure that at least one worksheet has been selected.
+ if ($this->_activesheet == 0) {
+ $this->_worksheets[0]->selected = 1;
+ }
+
+ // Calculate the number of selected worksheet tabs and call the finalization
+ // methods for each worksheet
+ $total_worksheets = count($this->_worksheets);
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ if ($this->_worksheets[$i]->selected) {
+ $this->_selected++;
+ }
+ $this->_worksheets[$i]->close($this->_sheetnames);
+ }
+
+ // Add Workbook globals
+ $this->_storeBof(0x0005);
+ $this->_storeCodepage();
+ if ($this->_BIFF_version == 0x0600) {
+ $this->_storeWindow1();
+ }
+ if ($this->_BIFF_version == 0x0500) {
+ $this->_storeExterns(); // For print area and repeat rows
+ }
+ $this->_storeNames(); // For print area and repeat rows
+ if ($this->_BIFF_version == 0x0500) {
+ $this->_storeWindow1();
+ }
+ $this->_storeDatemode();
+ $this->_storeAllFonts();
+ $this->_storeAllNumFormats();
+ $this->_storeAllXfs();
+ $this->_storeAllStyles();
+ $this->_storePalette();
+ $this->_calcSheetOffsets();
+
+ // Add BOUNDSHEET records
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ $this->_storeBoundsheet($this->_worksheets[$i]->name,$this->_worksheets[$i]->offset);
+ }
+
+ if ($this->_country_code != -1) {
+ $this->_storeCountry();
+ }
+
+ if ($this->_BIFF_version == 0x0600) {
+ //$this->_storeSupbookInternal();
+ /* TODO: store external SUPBOOK records and XCT and CRN records
+ in case of external references for BIFF8 */
+ //$this->_storeExternsheetBiff8();
+ $this->_storeSharedStringsTable();
+ }
+
+ // End Workbook globals
+ $this->_storeEof();
+
+ // Store the workbook in an OLE container
+ $res = $this->_storeOLEFile();
+ if ($this->isError($res)) {
+ return $this->raiseError($res->getMessage());
+ }
+ return true;
+ }
+
+ /**
+ * Store the workbook in an OLE container
+ *
+ * @access private
+ * @return mixed true on success. PEAR_Error on failure
+ */
+ function _storeOLEFile()
+ {
+ if($this->_BIFF_version == 0x0600) {
+ $OLE = new OLE_PPS_File(OLE::Asc2Ucs('Workbook'));
+ } else {
+ $OLE = new OLE_PPS_File(OLE::Asc2Ucs('Book'));
+ }
+ if ($this->_tmp_dir != '') {
+ $OLE->setTempDir($this->_tmp_dir);
+ }
+ $res = $OLE->init();
+ if ($this->isError($res)) {
+ return $this->raiseError("OLE Error: ".$res->getMessage());
+ }
+ $OLE->append($this->_data);
+
+ $total_worksheets = count($this->_worksheets);
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ while ($tmp = $this->_worksheets[$i]->getData()) {
+ $OLE->append($tmp);
+ }
+ }
+
+ $root = new OLE_PPS_Root(time(), time(), array($OLE));
+ if ($this->_tmp_dir != '') {
+ $root->setTempDir($this->_tmp_dir);
+ }
+
+ $res = $root->save($this->_filename);
+ if ($this->isError($res)) {
+ return $this->raiseError("OLE Error: ".$res->getMessage());
+ }
+ return true;
+ }
+
+ /**
+ * Calculate offsets for Worksheet BOF records.
+ *
+ * @access private
+ */
+ function _calcSheetOffsets()
+ {
+ if ($this->_BIFF_version == 0x0600) {
+ $boundsheet_length = 12; // fixed length for a BOUNDSHEET record
+ } else {
+ $boundsheet_length = 11;
+ }
+ $EOF = 4;
+ $offset = $this->_datasize;
+
+ if ($this->_BIFF_version == 0x0600) {
+ // add the length of the SST
+ /* TODO: check this works for a lot of strings (> 8224 bytes) */
+ $offset += $this->_calculateSharedStringsSizes();
+ if ($this->_country_code != -1) {
+ $offset += 8; // adding COUNTRY record
+ }
+ // add the lenght of SUPBOOK, EXTERNSHEET and NAME records
+ //$offset += 8; // FIXME: calculate real value when storing the records
+ }
+ $total_worksheets = count($this->_worksheets);
+ // add the length of the BOUNDSHEET records
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ $offset += $boundsheet_length + strlen($this->_worksheets[$i]->name);
+ }
+ $offset += $EOF;
+
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ $this->_worksheets[$i]->offset = $offset;
+ $offset += $this->_worksheets[$i]->_datasize;
+ }
+ $this->_biffsize = $offset;
+ }
+
+ /**
+ * Store the Excel FONT records.
+ *
+ * @access private
+ */
+ function _storeAllFonts()
+ {
+ // tmp_format is added by the constructor. We use this to write the default XF's
+ $format = $this->_tmp_format;
+ $font = $format->getFont();
+
+ // Note: Fonts are 0-indexed. According to the SDK there is no index 4,
+ // so the following fonts are 0, 1, 2, 3, 5
+ //
+ for ($i = 1; $i <= 5; $i++){
+ $this->_append($font);
+ }
+
+ // Iterate through the XF objects and write a FONT record if it isn't the
+ // same as the default FONT and if it hasn't already been used.
+ //
+ $fonts = array();
+ $index = 6; // The first user defined FONT
+
+ $key = $format->getFontKey(); // The default font from _tmp_format
+ $fonts[$key] = 0; // Index of the default font
+
+ $total_formats = count($this->_formats);
+ for ($i = 0; $i < $total_formats; $i++) {
+ $key = $this->_formats[$i]->getFontKey();
+ if (isset($fonts[$key])) {
+ // FONT has already been used
+ $this->_formats[$i]->font_index = $fonts[$key];
+ } else {
+ // Add a new FONT record
+ $fonts[$key] = $index;
+ $this->_formats[$i]->font_index = $index;
+ $index++;
+ $font = $this->_formats[$i]->getFont();
+ $this->_append($font);
+ }
+ }
+ }
+
+ /**
+ * Store user defined numerical formats i.e. FORMAT records
+ *
+ * @access private
+ */
+ function _storeAllNumFormats()
+ {
+ // Leaning num_format syndrome
+ $hash_num_formats = array();
+ $num_formats = array();
+ $index = 164;
+
+ // Iterate through the XF objects and write a FORMAT record if it isn't a
+ // built-in format type and if the FORMAT string hasn't already been used.
+ $total_formats = count($this->_formats);
+ for ($i = 0; $i < $total_formats; $i++) {
+ $num_format = $this->_formats[$i]->_num_format;
+
+ // Check if $num_format is an index to a built-in format.
+ // Also check for a string of zeros, which is a valid format string
+ // but would evaluate to zero.
+ //
+ if (!preg_match("/^0+\d/", $num_format)) {
+ if (preg_match("/^\d+$/", $num_format)) { // built-in format
+ continue;
+ }
+ }
+
+ if (isset($hash_num_formats[$num_format])) {
+ // FORMAT has already been used
+ $this->_formats[$i]->_num_format = $hash_num_formats[$num_format];
+ } else{
+ // Add a new FORMAT
+ $hash_num_formats[$num_format] = $index;
+ $this->_formats[$i]->_num_format = $index;
+ array_push($num_formats,$num_format);
+ $index++;
+ }
+ }
+
+ // Write the new FORMAT records starting from 0xA4
+ $index = 164;
+ foreach ($num_formats as $num_format) {
+ $this->_storeNumFormat($num_format,$index);
+ $index++;
+ }
+ }
+
+ /**
+ * Write all XF records.
+ *
+ * @access private
+ */
+ function _storeAllXfs()
+ {
+ // _tmp_format is added by the constructor. We use this to write the default XF's
+ // The default font index is 0
+ //
+ $format = $this->_tmp_format;
+ for ($i = 0; $i <= 14; $i++) {
+ $xf = $format->getXf('style'); // Style XF
+ $this->_append($xf);
+ }
+
+ $xf = $format->getXf('cell'); // Cell XF
+ $this->_append($xf);
+
+ // User defined XFs
+ $total_formats = count($this->_formats);
+ for ($i = 0; $i < $total_formats; $i++) {
+ $xf = $this->_formats[$i]->getXf('cell');
+ $this->_append($xf);
+ }
+ }
+
+ /**
+ * Write all STYLE records.
+ *
+ * @access private
+ */
+ function _storeAllStyles()
+ {
+ $this->_storeStyle();
+ }
+
+ /**
+ * Write the EXTERNCOUNT and EXTERNSHEET records. These are used as indexes for
+ * the NAME records.
+ *
+ * @access private
+ */
+ function _storeExterns()
+
+ {
+ // Create EXTERNCOUNT with number of worksheets
+ $this->_storeExterncount(count($this->_worksheets));
+
+ // Create EXTERNSHEET for each worksheet
+ foreach ($this->_sheetnames as $sheetname) {
+ $this->_storeExternsheet($sheetname);
+ }
+ }
+
+ /**
+ * Write the NAME record to define the print area and the repeat rows and cols.
+ *
+ * @access private
+ */
+ function _storeNames()
+ {
+ // Create the print area NAME records
+ $total_worksheets = count($this->_worksheets);
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ // Write a Name record if the print area has been defined
+ if (isset($this->_worksheets[$i]->print_rowmin)) {
+ $this->_storeNameShort(
+ $this->_worksheets[$i]->index,
+ 0x06, // NAME type
+ $this->_worksheets[$i]->print_rowmin,
+ $this->_worksheets[$i]->print_rowmax,
+ $this->_worksheets[$i]->print_colmin,
+ $this->_worksheets[$i]->print_colmax
+ );
+ }
+ }
+
+ // Create the print title NAME records
+ $total_worksheets = count($this->_worksheets);
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ $rowmin = $this->_worksheets[$i]->title_rowmin;
+ $rowmax = $this->_worksheets[$i]->title_rowmax;
+ $colmin = $this->_worksheets[$i]->title_colmin;
+ $colmax = $this->_worksheets[$i]->title_colmax;
+
+ // Determine if row + col, row, col or nothing has been defined
+ // and write the appropriate record
+ //
+ if (isset($rowmin) && isset($colmin)) {
+ // Row and column titles have been defined.
+ // Row title has been defined.
+ $this->_storeNameLong(
+ $this->_worksheets[$i]->index,
+ 0x07, // NAME type
+ $rowmin,
+ $rowmax,
+ $colmin,
+ $colmax
+ );
+ } elseif (isset($rowmin)) {
+ // Row title has been defined.
+ $this->_storeNameShort(
+ $this->_worksheets[$i]->index,
+ 0x07, // NAME type
+ $rowmin,
+ $rowmax,
+ 0x00,
+ 0xff
+ );
+ } elseif (isset($colmin)) {
+ // Column title has been defined.
+ $this->_storeNameShort(
+ $this->_worksheets[$i]->index,
+ 0x07, // NAME type
+ 0x0000,
+ 0x3fff,
+ $colmin,
+ $colmax
+ );
+ } else {
+ // Print title hasn't been defined.
+ }
+ }
+ }
+
+
+
+
+ /******************************************************************************
+ *
+ * BIFF RECORDS
+ *
+ */
+
+ /**
+ * Stores the CODEPAGE biff record.
+ *
+ * @access private
+ */
+ function _storeCodepage()
+ {
+ $record = 0x0042; // Record identifier
+ $length = 0x0002; // Number of bytes to follow
+ $cv = $this->_codepage; // The code page
+
+ $header = pack('vv', $record, $length);
+ $data = pack('v', $cv);
+
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Write Excel BIFF WINDOW1 record.
+ *
+ * @access private
+ */
+ function _storeWindow1()
+ {
+ $record = 0x003D; // Record identifier
+ $length = 0x0012; // Number of bytes to follow
+
+ $xWn = 0x0000; // Horizontal position of window
+ $yWn = 0x0000; // Vertical position of window
+ $dxWn = 0x25BC; // Width of window
+ $dyWn = 0x1572; // Height of window
+
+ $grbit = 0x0038; // Option flags
+ $ctabsel = $this->_selected; // Number of workbook tabs selected
+ $wTabRatio = 0x0258; // Tab to scrollbar ratio
+
+ $itabFirst = $this->_firstsheet; // 1st displayed worksheet
+ $itabCur = $this->_activesheet; // Active worksheet
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvvvvvvv", $xWn, $yWn, $dxWn, $dyWn,
+ $grbit,
+ $itabCur, $itabFirst,
+ $ctabsel, $wTabRatio);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Writes Excel BIFF BOUNDSHEET record.
+ * FIXME: inconsistent with BIFF documentation
+ *
+ * @param string $sheetname Worksheet name
+ * @param integer $offset Location of worksheet BOF
+ * @access private
+ */
+ function _storeBoundsheet($sheetname,$offset)
+ {
+ $record = 0x0085; // Record identifier
+ if ($this->_BIFF_version == 0x0600) {
+ $length = 0x08 + strlen($sheetname); // Number of bytes to follow
+ } else {
+ $length = 0x07 + strlen($sheetname); // Number of bytes to follow
+ }
+
+ $grbit = 0x0000; // Visibility and sheet type
+ if ($this->_BIFF_version == 0x0600) {
+ $cch = mb_strlen($sheetname,'UTF-16LE'); // Length of sheet name
+ } else {
+ $cch = strlen($sheetname); // Length of sheet name
+ }
+
+ $header = pack("vv", $record, $length);
+ if ($this->_BIFF_version == 0x0600) {
+ $data = pack("VvCC", $offset, $grbit, $cch, 0x1);
+ } else {
+ $data = pack("VvC", $offset, $grbit, $cch);
+ }
+ $this->_append($header.$data.$sheetname);
+ }
+
+ /**
+ * Write Internal SUPBOOK record
+ *
+ * @access private
+ */
+ function _storeSupbookInternal()
+ {
+ $record = 0x01AE; // Record identifier
+ $length = 0x0004; // Bytes to follow
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vv", count($this->_worksheets), 0x0104);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Writes the Excel BIFF EXTERNSHEET record. These references are used by
+ * formulas.
+ *
+ * @param string $sheetname Worksheet name
+ * @access private
+ */
+ function _storeExternsheetBiff8()
+ {
+ $total_references = count($this->_parser->_references);
+ $record = 0x0017; // Record identifier
+ $length = 2 + 6 * $total_references; // Number of bytes to follow
+
+ $supbook_index = 0; // FIXME: only using internal SUPBOOK record
+ $header = pack("vv", $record, $length);
+ $data = pack('v', $total_references);
+ for ($i = 0; $i < $total_references; $i++) {
+ $data .= $this->_parser->_references[$i];
+ }
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Write Excel BIFF STYLE records.
+ *
+ * @access private
+ */
+ function _storeStyle()
+ {
+ $record = 0x0293; // Record identifier
+ $length = 0x0004; // Bytes to follow
+
+ $ixfe = 0x8000; // Index to style XF
+ $BuiltIn = 0x00; // Built-in style
+ $iLevel = 0xff; // Outline style level
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vCC", $ixfe, $BuiltIn, $iLevel);
+ $this->_append($header . $data);
+ }
+
+
+ /**
+ * Writes Excel FORMAT record for non "built-in" numerical formats.
+ *
+ * @param string $format Custom format string
+ * @param integer $ifmt Format index code
+ * @access private
+ */
+ function _storeNumFormat($format, $ifmt)
+ {
+ $record = 0x041E; // Record identifier
+
+ if ($this->_BIFF_version == 0x0600) {
+ $length = 5 + strlen($format); // Number of bytes to follow
+ $encoding = 0x0;
+ } elseif ($this->_BIFF_version == 0x0500) {
+ $length = 3 + strlen($format); // Number of bytes to follow
+ }
+
+ if ( $this->_BIFF_version == 0x0600 && function_exists('iconv') ) { // Encode format String
+ if (mb_detect_encoding($format, 'auto') !== 'UTF-16LE'){
+ $format = iconv(mb_detect_encoding($format, 'auto'),'UTF-16LE',$format);
+ }
+ $encoding = 1;
+ $cch = function_exists('mb_strlen') ? mb_strlen($format, 'UTF-16LE') : (strlen($format) / 2);
+ } else {
+ $encoding = 0;
+ $cch = strlen($format); // Length of format string
+ }
+ $length = strlen($format);
+
+ if ($this->_BIFF_version == 0x0600) {
+ $header = pack("vv", $record, 5 + $length);
+ $data = pack("vvC", $ifmt, $cch, $encoding);
+ } elseif ($this->_BIFF_version == 0x0500) {
+ $header = pack("vv", $record, 3 + $length);
+ $data = pack("vC", $ifmt, $cch);
+ }
+ $this->_append($header . $data . $format);
+ }
+
+ /**
+ * Write DATEMODE record to indicate the date system in use (1904 or 1900).
+ *
+ * @access private
+ */
+ function _storeDatemode()
+ {
+ $record = 0x0022; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $f1904 = $this->_1904; // Flag for 1904 date system
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $f1904);
+ $this->_append($header . $data);
+ }
+
+
+ /**
+ * Write BIFF record EXTERNCOUNT to indicate the number of external sheet
+ * references in the workbook.
+ *
+ * Excel only stores references to external sheets that are used in NAME.
+ * The workbook NAME record is required to define the print area and the repeat
+ * rows and columns.
+ *
+ * A similar method is used in Worksheet.php for a slightly different purpose.
+ *
+ * @param integer $cxals Number of external references
+ * @access private
+ */
+ function _storeExterncount($cxals)
+ {
+ $record = 0x0016; // Record identifier
+ $length = 0x0002; // Number of bytes to follow
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $cxals);
+ $this->_append($header . $data);
+ }
+
+
+ /**
+ * Writes the Excel BIFF EXTERNSHEET record. These references are used by
+ * formulas. NAME record is required to define the print area and the repeat
+ * rows and columns.
+ *
+ * A similar method is used in Worksheet.php for a slightly different purpose.
+ *
+ * @param string $sheetname Worksheet name
+ * @access private
+ */
+ function _storeExternsheet($sheetname)
+ {
+ $record = 0x0017; // Record identifier
+ $length = 0x02 + strlen($sheetname); // Number of bytes to follow
+
+ $cch = strlen($sheetname); // Length of sheet name
+ $rgch = 0x03; // Filename encoding
+
+ $header = pack("vv", $record, $length);
+ $data = pack("CC", $cch, $rgch);
+ $this->_append($header . $data . $sheetname);
+ }
+
+
+ /**
+ * Store the NAME record in the short format that is used for storing the print
+ * area, repeat rows only and repeat columns only.
+ *
+ * @param integer $index Sheet index
+ * @param integer $type Built-in name type
+ * @param integer $rowmin Start row
+ * @param integer $rowmax End row
+ * @param integer $colmin Start colum
+ * @param integer $colmax End column
+ * @access private
+ */
+ function _storeNameShort($index, $type, $rowmin, $rowmax, $colmin, $colmax)
+ {
+ $record = 0x0018; // Record identifier
+ $length = 0x0024; // Number of bytes to follow
+
+ $grbit = 0x0020; // Option flags
+ $chKey = 0x00; // Keyboard shortcut
+ $cch = 0x01; // Length of text name
+ $cce = 0x0015; // Length of text definition
+ $ixals = $index + 1; // Sheet index
+ $itab = $ixals; // Equal to ixals
+ $cchCustMenu = 0x00; // Length of cust menu text
+ $cchDescription = 0x00; // Length of description text
+ $cchHelptopic = 0x00; // Length of help topic text
+ $cchStatustext = 0x00; // Length of status bar text
+ $rgch = $type; // Built-in name type
+
+ $unknown03 = 0x3b;
+ $unknown04 = 0xffff-$index;
+ $unknown05 = 0x0000;
+ $unknown06 = 0x0000;
+ $unknown07 = 0x1087;
+ $unknown08 = 0x8005;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $grbit);
+ $data .= pack("C", $chKey);
+ $data .= pack("C", $cch);
+ $data .= pack("v", $cce);
+ $data .= pack("v", $ixals);
+ $data .= pack("v", $itab);
+ $data .= pack("C", $cchCustMenu);
+ $data .= pack("C", $cchDescription);
+ $data .= pack("C", $cchHelptopic);
+ $data .= pack("C", $cchStatustext);
+ $data .= pack("C", $rgch);
+ $data .= pack("C", $unknown03);
+ $data .= pack("v", $unknown04);
+ $data .= pack("v", $unknown05);
+ $data .= pack("v", $unknown06);
+ $data .= pack("v", $unknown07);
+ $data .= pack("v", $unknown08);
+ $data .= pack("v", $index);
+ $data .= pack("v", $index);
+ $data .= pack("v", $rowmin);
+ $data .= pack("v", $rowmax);
+ $data .= pack("C", $colmin);
+ $data .= pack("C", $colmax);
+ $this->_append($header . $data);
+ }
+
+
+ /**
+ * Store the NAME record in the long format that is used for storing the repeat
+ * rows and columns when both are specified. This shares a lot of code with
+ * _storeNameShort() but we use a separate method to keep the code clean.
+ * Code abstraction for reuse can be carried too far, and I should know. ;-)
+ *
+ * @param integer $index Sheet index
+ * @param integer $type Built-in name type
+ * @param integer $rowmin Start row
+ * @param integer $rowmax End row
+ * @param integer $colmin Start colum
+ * @param integer $colmax End column
+ * @access private
+ */
+ function _storeNameLong($index, $type, $rowmin, $rowmax, $colmin, $colmax)
+ {
+ $record = 0x0018; // Record identifier
+ $length = 0x003d; // Number of bytes to follow
+ $grbit = 0x0020; // Option flags
+ $chKey = 0x00; // Keyboard shortcut
+ $cch = 0x01; // Length of text name
+ $cce = 0x002e; // Length of text definition
+ $ixals = $index + 1; // Sheet index
+ $itab = $ixals; // Equal to ixals
+ $cchCustMenu = 0x00; // Length of cust menu text
+ $cchDescription = 0x00; // Length of description text
+ $cchHelptopic = 0x00; // Length of help topic text
+ $cchStatustext = 0x00; // Length of status bar text
+ $rgch = $type; // Built-in name type
+
+ $unknown01 = 0x29;
+ $unknown02 = 0x002b;
+ $unknown03 = 0x3b;
+ $unknown04 = 0xffff-$index;
+ $unknown05 = 0x0000;
+ $unknown06 = 0x0000;
+ $unknown07 = 0x1087;
+ $unknown08 = 0x8008;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $grbit);
+ $data .= pack("C", $chKey);
+ $data .= pack("C", $cch);
+ $data .= pack("v", $cce);
+ $data .= pack("v", $ixals);
+ $data .= pack("v", $itab);
+ $data .= pack("C", $cchCustMenu);
+ $data .= pack("C", $cchDescription);
+ $data .= pack("C", $cchHelptopic);
+ $data .= pack("C", $cchStatustext);
+ $data .= pack("C", $rgch);
+ $data .= pack("C", $unknown01);
+ $data .= pack("v", $unknown02);
+ // Column definition
+ $data .= pack("C", $unknown03);
+ $data .= pack("v", $unknown04);
+ $data .= pack("v", $unknown05);
+ $data .= pack("v", $unknown06);
+ $data .= pack("v", $unknown07);
+ $data .= pack("v", $unknown08);
+ $data .= pack("v", $index);
+ $data .= pack("v", $index);
+ $data .= pack("v", 0x0000);
+ $data .= pack("v", 0x3fff);
+ $data .= pack("C", $colmin);
+ $data .= pack("C", $colmax);
+ // Row definition
+ $data .= pack("C", $unknown03);
+ $data .= pack("v", $unknown04);
+ $data .= pack("v", $unknown05);
+ $data .= pack("v", $unknown06);
+ $data .= pack("v", $unknown07);
+ $data .= pack("v", $unknown08);
+ $data .= pack("v", $index);
+ $data .= pack("v", $index);
+ $data .= pack("v", $rowmin);
+ $data .= pack("v", $rowmax);
+ $data .= pack("C", 0x00);
+ $data .= pack("C", 0xff);
+ // End of data
+ $data .= pack("C", 0x10);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Stores the COUNTRY record for localization
+ *
+ * @access private
+ */
+ function _storeCountry()
+ {
+ $record = 0x008C; // Record identifier
+ $length = 4; // Number of bytes to follow
+
+ $header = pack('vv', $record, $length);
+ /* using the same country code always for simplicity */
+ $data = pack('vv', $this->_country_code, $this->_country_code);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Stores the PALETTE biff record.
+ *
+ * @access private
+ */
+ function _storePalette()
+ {
+ $aref = $this->_palette;
+
+ $record = 0x0092; // Record identifier
+ $length = 2 + 4 * count($aref); // Number of bytes to follow
+ $ccv = count($aref); // Number of RGB values to follow
+ $data = ''; // The RGB data
+
+ // Pack the RGB data
+ foreach ($aref as $color) {
+ foreach ($color as $byte) {
+ $data .= pack("C",$byte);
+ }
+ }
+
+ $header = pack("vvv", $record, $length, $ccv);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Calculate
+ * Handling of the SST continue blocks is complicated by the need to include an
+ * additional continuation byte depending on whether the string is split between
+ * blocks or whether it starts at the beginning of the block. (There are also
+ * additional complications that will arise later when/if Rich Strings are
+ * supported).
+ *
+ * @access private
+ */
+ function _calculateSharedStringsSizes()
+ {
+ /* Iterate through the strings to calculate the CONTINUE block sizes.
+ For simplicity we use the same size for the SST and CONTINUE records:
+ 8228 : Maximum Excel97 block size
+ -4 : Length of block header
+ -8 : Length of additional SST header information
+ -8 : Arbitrary number to keep within _add_continue() limit = 8208
+ */
+ $continue_limit = 8208;
+ $block_length = 0;
+ $written = 0;
+ $this->_block_sizes = array();
+ $continue = 0;
+
+ foreach (array_keys($this->_str_table) as $string) {
+ $string_length = strlen($string);
+ $headerinfo = unpack("vlength/Cencoding", $string);
+ $encoding = $headerinfo["encoding"];
+ $split_string = 0;
+
+ // Block length is the total length of the strings that will be
+ // written out in a single SST or CONTINUE block.
+ $block_length += $string_length;
+
+ // We can write the string if it doesn't cross a CONTINUE boundary
+ if ($block_length < $continue_limit) {
+ $written += $string_length;
+ continue;
+ }
+
+ // Deal with the cases where the next string to be written will exceed
+ // the CONTINUE boundary. If the string is very long it may need to be
+ // written in more than one CONTINUE record.
+ while ($block_length >= $continue_limit) {
+
+ // We need to avoid the case where a string is continued in the first
+ // n bytes that contain the string header information.
+ $header_length = 3; // Min string + header size -1
+ $space_remaining = $continue_limit - $written - $continue;
+
+
+ /* TODO: Unicode data should only be split on char (2 byte)
+ boundaries. Therefore, in some cases we need to reduce the
+ amount of available
+ */
+ $align = 0;
+
+ // Only applies to Unicode strings
+ if ($encoding == 1) {
+ // Min string + header size -1
+ $header_length = 4;
+
+ if ($space_remaining > $header_length) {
+ // String contains 3 byte header => split on odd boundary
+ if (!$split_string && $space_remaining % 2 != 1) {
+ $space_remaining--;
+ $align = 1;
+ }
+ // Split section without header => split on even boundary
+ else if ($split_string && $space_remaining % 2 == 1) {
+ $space_remaining--;
+ $align = 1;
+ }
+
+ $split_string = 1;
+ }
+ }
+
+
+ if ($space_remaining > $header_length) {
+ // Write as much as possible of the string in the current block
+ $written += $space_remaining;
+
+ // Reduce the current block length by the amount written
+ $block_length -= $continue_limit - $continue - $align;
+
+ // Store the max size for this block
+ $this->_block_sizes[] = $continue_limit - $align;
+
+ // If the current string was split then the next CONTINUE block
+ // should have the string continue flag (grbit) set unless the
+ // split string fits exactly into the remaining space.
+ if ($block_length > 0) {
+ $continue = 1;
+ } else {
+ $continue = 0;
+ }
+ } else {
+ // Store the max size for this block
+ $this->_block_sizes[] = $written + $continue;
+
+ // Not enough space to start the string in the current block
+ $block_length -= $continue_limit - $space_remaining - $continue;
+ $continue = 0;
+
+ }
+
+ // If the string (or substr) is small enough we can write it in the
+ // new CONTINUE block. Else, go through the loop again to write it in
+ // one or more CONTINUE blocks
+ if ($block_length < $continue_limit) {
+ $written = $block_length;
+ } else {
+ $written = 0;
+ }
+ }
+ }
+
+ // Store the max size for the last block unless it is empty
+ if ($written + $continue) {
+ $this->_block_sizes[] = $written + $continue;
+ }
+
+
+ /* Calculate the total length of the SST and associated CONTINUEs (if any).
+ The SST record will have a length even if it contains no strings.
+ This length is required to set the offsets in the BOUNDSHEET records since
+ they must be written before the SST records
+ */
+
+ $tmp_block_sizes = array();
+ $tmp_block_sizes = $this->_block_sizes;
+
+ $length = 12;
+ if (!empty($tmp_block_sizes)) {
+ $length += array_shift($tmp_block_sizes); // SST
+ }
+ while (!empty($tmp_block_sizes)) {
+ $length += 4 + array_shift($tmp_block_sizes); // CONTINUEs
+ }
+
+ return $length;
+ }
+
+ /**
+ * Write all of the workbooks strings into an indexed array.
+ * See the comments in _calculate_shared_string_sizes() for more information.
+ *
+ * The Excel documentation says that the SST record should be followed by an
+ * EXTSST record. The EXTSST record is a hash table that is used to optimise
+ * access to SST. However, despite the documentation it doesn't seem to be
+ * required so we will ignore it.
+ *
+ * @access private
+ */
+ function _storeSharedStringsTable()
+ {
+ $record = 0x00fc; // Record identifier
+ $length = 0x0008; // Number of bytes to follow
+ $total = 0x0000;
+
+ // Iterate through the strings to calculate the CONTINUE block sizes
+ $continue_limit = 8208;
+ $block_length = 0;
+ $written = 0;
+ $continue = 0;
+
+ // sizes are upside down
+ $tmp_block_sizes = $this->_block_sizes;
+ // $tmp_block_sizes = array_reverse($this->_block_sizes);
+
+ // The SST record is required even if it contains no strings. Thus we will
+ // always have a length
+ //
+ if (!empty($tmp_block_sizes)) {
+ $length = 8 + array_shift($tmp_block_sizes);
+ }
+ else {
+ // No strings
+ $length = 8;
+ }
+
+
+
+ // Write the SST block header information
+ $header = pack("vv", $record, $length);
+ $data = pack("VV", $this->_str_total, $this->_str_unique);
+ $this->_append($header . $data);
+
+
+
+
+ /* TODO: not good for performance */
+ foreach (array_keys($this->_str_table) as $string) {
+
+ $string_length = strlen($string);
+ $headerinfo = unpack("vlength/Cencoding", $string);
+ $encoding = $headerinfo["encoding"];
+ $split_string = 0;
+
+ // Block length is the total length of the strings that will be
+ // written out in a single SST or CONTINUE block.
+ //
+ $block_length += $string_length;
+
+
+ // We can write the string if it doesn't cross a CONTINUE boundary
+ if ($block_length < $continue_limit) {
+ $this->_append($string);
+ $written += $string_length;
+ continue;
+ }
+
+ // Deal with the cases where the next string to be written will exceed
+ // the CONTINUE boundary. If the string is very long it may need to be
+ // written in more than one CONTINUE record.
+ //
+ while ($block_length >= $continue_limit) {
+
+ // We need to avoid the case where a string is continued in the first
+ // n bytes that contain the string header information.
+ //
+ $header_length = 3; // Min string + header size -1
+ $space_remaining = $continue_limit - $written - $continue;
+
+
+ // Unicode data should only be split on char (2 byte) boundaries.
+ // Therefore, in some cases we need to reduce the amount of available
+ // space by 1 byte to ensure the correct alignment.
+ $align = 0;
+
+ // Only applies to Unicode strings
+ if ($encoding == 1) {
+ // Min string + header size -1
+ $header_length = 4;
+
+ if ($space_remaining > $header_length) {
+ // String contains 3 byte header => split on odd boundary
+ if (!$split_string && $space_remaining % 2 != 1) {
+ $space_remaining--;
+ $align = 1;
+ }
+ // Split section without header => split on even boundary
+ else if ($split_string && $space_remaining % 2 == 1) {
+ $space_remaining--;
+ $align = 1;
+ }
+
+ $split_string = 1;
+ }
+ }
+
+
+ if ($space_remaining > $header_length) {
+ // Write as much as possible of the string in the current block
+ $tmp = substr($string, 0, $space_remaining);
+ $this->_append($tmp);
+
+ // The remainder will be written in the next block(s)
+ $string = substr($string, $space_remaining);
+
+ // Reduce the current block length by the amount written
+ $block_length -= $continue_limit - $continue - $align;
+
+ // If the current string was split then the next CONTINUE block
+ // should have the string continue flag (grbit) set unless the
+ // split string fits exactly into the remaining space.
+ //
+ if ($block_length > 0) {
+ $continue = 1;
+ } else {
+ $continue = 0;
+ }
+ } else {
+ // Not enough space to start the string in the current block
+ $block_length -= $continue_limit - $space_remaining - $continue;
+ $continue = 0;
+ }
+
+ // Write the CONTINUE block header
+ if (!empty($this->_block_sizes)) {
+ $record = 0x003C;
+ $length = array_shift($tmp_block_sizes);
+
+ $header = pack('vv', $record, $length);
+ if ($continue) {
+ $header .= pack('C', $encoding);
+ }
+ $this->_append($header);
+ }
+
+ // If the string (or substr) is small enough we can write it in the
+ // new CONTINUE block. Else, go through the loop again to write it in
+ // one or more CONTINUE blocks
+ //
+ if ($block_length < $continue_limit) {
+ $this->_append($string);
+ $written = $block_length;
+ } else {
+ $written = 0;
+ }
+ }
+ }
+ }
+
+
+}
+
diff --git a/vendor/library/Excel/Writer/Worksheet.php b/vendor/library/Excel/Writer/Worksheet.php
new file mode 100644
index 0000000..179f67b
--- /dev/null
+++ b/vendor/library/Excel/Writer/Worksheet.php
@@ -0,0 +1,3596 @@
+
+*
+* The majority of this is _NOT_ my code. I simply ported it from the
+* PERL Spreadsheet::WriteExcel module.
+*
+* The author of the Spreadsheet::WriteExcel module is John McNamara
+*
+*
+* I _DO_ maintain this code, and John McNamara has nothing to do with the
+* porting of this code to PHP. Any questions directly related to this
+* class library should be directed to me.
+*
+* License Information:
+*
+* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
+* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+require_once 'Spreadsheet/Excel/Writer/Parser.php';
+require_once 'Spreadsheet/Excel/Writer/BIFFwriter.php';
+
+/**
+* Class for generating Excel Spreadsheets
+*
+* @author Xavier Noguer
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+
+class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwriter
+{
+ /**
+ * Name of the Worksheet
+ * @var string
+ */
+ var $name;
+
+ /**
+ * Index for the Worksheet
+ * @var integer
+ */
+ var $index;
+
+ /**
+ * Reference to the (default) Format object for URLs
+ * @var object Format
+ */
+ var $_url_format;
+
+ /**
+ * Reference to the parser used for parsing formulas
+ * @var object Format
+ */
+ var $_parser;
+
+ /**
+ * Filehandle to the temporary file for storing data
+ * @var resource
+ */
+ var $_filehandle;
+
+ /**
+ * Boolean indicating if we are using a temporary file for storing data
+ * @var bool
+ */
+ var $_using_tmpfile;
+
+ /**
+ * Maximum number of rows for an Excel spreadsheet (BIFF5)
+ * @var integer
+ */
+ var $_xls_rowmax;
+
+ /**
+ * Maximum number of columns for an Excel spreadsheet (BIFF5)
+ * @var integer
+ */
+ var $_xls_colmax;
+
+ /**
+ * Maximum number of characters for a string (LABEL record in BIFF5)
+ * @var integer
+ */
+ var $_xls_strmax;
+
+ /**
+ * First row for the DIMENSIONS record
+ * @var integer
+ * @see _storeDimensions()
+ */
+ var $_dim_rowmin;
+
+ /**
+ * Last row for the DIMENSIONS record
+ * @var integer
+ * @see _storeDimensions()
+ */
+ var $_dim_rowmax;
+
+ /**
+ * First column for the DIMENSIONS record
+ * @var integer
+ * @see _storeDimensions()
+ */
+ var $_dim_colmin;
+
+ /**
+ * Last column for the DIMENSIONS record
+ * @var integer
+ * @see _storeDimensions()
+ */
+ var $_dim_colmax;
+
+ /**
+ * Array containing format information for columns
+ * @var array
+ */
+ var $_colinfo;
+
+ /**
+ * Array containing the selected area for the worksheet
+ * @var array
+ */
+ var $_selection;
+
+ /**
+ * Array containing the panes for the worksheet
+ * @var array
+ */
+ var $_panes;
+
+ /**
+ * The active pane for the worksheet
+ * @var integer
+ */
+ var $_active_pane;
+
+ /**
+ * Bit specifying if panes are frozen
+ * @var integer
+ */
+ var $_frozen;
+
+ /**
+ * Bit specifying if the worksheet is selected
+ * @var integer
+ */
+ var $selected;
+
+ /**
+ * The paper size (for printing) (DOCUMENT!!!)
+ * @var integer
+ */
+ var $_paper_size;
+
+ /**
+ * Bit specifying paper orientation (for printing). 0 => landscape, 1 => portrait
+ * @var integer
+ */
+ var $_orientation;
+
+ /**
+ * The page header caption
+ * @var string
+ */
+ var $_header;
+
+ /**
+ * The page footer caption
+ * @var string
+ */
+ var $_footer;
+
+ /**
+ * The horizontal centering value for the page
+ * @var integer
+ */
+ var $_hcenter;
+
+ /**
+ * The vertical centering value for the page
+ * @var integer
+ */
+ var $_vcenter;
+
+ /**
+ * The margin for the header
+ * @var float
+ */
+ var $_margin_head;
+
+ /**
+ * The margin for the footer
+ * @var float
+ */
+ var $_margin_foot;
+
+ /**
+ * The left margin for the worksheet in inches
+ * @var float
+ */
+ var $_margin_left;
+
+ /**
+ * The right margin for the worksheet in inches
+ * @var float
+ */
+ var $_margin_right;
+
+ /**
+ * The top margin for the worksheet in inches
+ * @var float
+ */
+ var $_margin_top;
+
+ /**
+ * The bottom margin for the worksheet in inches
+ * @var float
+ */
+ var $_margin_bottom;
+
+ /**
+ * First row to reapeat on each printed page
+ * @var integer
+ */
+ var $title_rowmin;
+
+ /**
+ * Last row to reapeat on each printed page
+ * @var integer
+ */
+ var $title_rowmax;
+
+ /**
+ * First column to reapeat on each printed page
+ * @var integer
+ */
+ var $title_colmin;
+
+ /**
+ * First row of the area to print
+ * @var integer
+ */
+ var $print_rowmin;
+
+ /**
+ * Last row to of the area to print
+ * @var integer
+ */
+ var $print_rowmax;
+
+ /**
+ * First column of the area to print
+ * @var integer
+ */
+ var $print_colmin;
+
+ /**
+ * Last column of the area to print
+ * @var integer
+ */
+ var $print_colmax;
+
+ /**
+ * Whether to display RightToLeft.
+ * @var integer
+ */
+ var $_Arabic;
+
+ /**
+ * Whether to use outline.
+ * @var integer
+ */
+ var $_outline_on;
+
+ /**
+ * Auto outline styles.
+ * @var bool
+ */
+ var $_outline_style;
+
+ /**
+ * Whether to have outline summary below.
+ * @var bool
+ */
+ var $_outline_below;
+
+ /**
+ * Whether to have outline summary at the right.
+ * @var bool
+ */
+ var $_outline_right;
+
+ /**
+ * Outline row level.
+ * @var integer
+ */
+ var $_outline_row_level;
+
+ /**
+ * Whether to fit to page when printing or not.
+ * @var bool
+ */
+ var $_fit_page;
+
+ /**
+ * Number of pages to fit wide
+ * @var integer
+ */
+ var $_fit_width;
+
+ /**
+ * Number of pages to fit high
+ * @var integer
+ */
+ var $_fit_height;
+
+ /**
+ * Reference to the total number of strings in the workbook
+ * @var integer
+ */
+ var $_str_total;
+
+ /**
+ * Reference to the number of unique strings in the workbook
+ * @var integer
+ */
+ var $_str_unique;
+
+ /**
+ * Reference to the array containing all the unique strings in the workbook
+ * @var array
+ */
+ var $_str_table;
+
+ /**
+ * Number of merged cell ranges in actual record
+ * @var int $_merged_cells_counter
+ */
+ var $_merged_cells_counter = 0;
+
+ /**
+ * Number of actual mergedcells record
+ * @var int $_merged_cells_record
+ */
+ var $_merged_cells_record = 0;
+
+ /**
+ * Merged cell ranges
+ * @var array
+ */
+ var $_merged_ranges;
+
+ /**
+ * Charset encoding currently used when calling writeString()
+ * @var string
+ */
+ var $_input_encoding;
+
+ /**
+ * Constructor
+ *
+ * @param string $name The name of the new worksheet
+ * @param integer $index The index of the new worksheet
+ * @param mixed &$activesheet The current activesheet of the workbook we belong to
+ * @param mixed &$firstsheet The first worksheet in the workbook we belong to
+ * @param mixed &$url_format The default format for hyperlinks
+ * @param mixed &$parser The formula parser created for the Workbook
+ * @param string $tmp_dir The path to the directory for temporary files
+ * @access private
+ */
+ function Spreadsheet_Excel_Writer_Worksheet($BIFF_version, $name,
+ $index, &$activesheet,
+ &$firstsheet, &$str_total,
+ &$str_unique, &$str_table,
+ &$url_format, &$parser,
+ $tmp_dir)
+ {
+ // It needs to call its parent's constructor explicitly
+ $this->Spreadsheet_Excel_Writer_BIFFwriter();
+ $this->_BIFF_version = $BIFF_version;
+ $rowmax = 65536; // 16384 in Excel 5
+ $colmax = 256;
+
+ $this->name = $name;
+ $this->index = $index;
+ $this->activesheet = &$activesheet;
+ $this->firstsheet = &$firstsheet;
+ $this->_str_total = &$str_total;
+ $this->_str_unique = &$str_unique;
+ $this->_str_table = &$str_table;
+ $this->_url_format = &$url_format;
+ $this->_parser = &$parser;
+
+ //$this->ext_sheets = array();
+ $this->_filehandle = '';
+ $this->_using_tmpfile = true;
+ //$this->fileclosed = 0;
+ //$this->offset = 0;
+ $this->_xls_rowmax = $rowmax;
+ $this->_xls_colmax = $colmax;
+ $this->_xls_strmax = 255;
+ $this->_dim_rowmin = $rowmax + 1;
+ $this->_dim_rowmax = 0;
+ $this->_dim_colmin = $colmax + 1;
+ $this->_dim_colmax = 0;
+ $this->_colinfo = array();
+ $this->_selection = array(0,0,0,0);
+ $this->_panes = array();
+ $this->_active_pane = 3;
+ $this->_frozen = 0;
+ $this->selected = 0;
+
+ $this->_paper_size = 0x0;
+ $this->_orientation = 0x1;
+ $this->_header = '';
+ $this->_footer = '';
+ $this->_hcenter = 0;
+ $this->_vcenter = 0;
+ $this->_margin_head = 0.50;
+ $this->_margin_foot = 0.50;
+ $this->_margin_left = 0.75;
+ $this->_margin_right = 0.75;
+ $this->_margin_top = 1.00;
+ $this->_margin_bottom = 1.00;
+
+ $this->title_rowmin = null;
+ $this->title_rowmax = null;
+ $this->title_colmin = null;
+ $this->title_colmax = null;
+ $this->print_rowmin = null;
+ $this->print_rowmax = null;
+ $this->print_colmin = null;
+ $this->print_colmax = null;
+
+ $this->_print_gridlines = 1;
+ $this->_screen_gridlines = 1;
+ $this->_print_headers = 0;
+
+ $this->_fit_page = 0;
+ $this->_fit_width = 0;
+ $this->_fit_height = 0;
+
+ $this->_hbreaks = array();
+ $this->_vbreaks = array();
+
+ $this->_protect = 0;
+ $this->_password = null;
+
+ $this->col_sizes = array();
+ $this->_row_sizes = array();
+
+ $this->_zoom = 100;
+ $this->_print_scale = 100;
+
+ $this->_outline_row_level = 0;
+ $this->_outline_style = 0;
+ $this->_outline_below = 1;
+ $this->_outline_right = 1;
+ $this->_outline_on = 1;
+ $this->_Arabic = 0;
+
+ $this->_merged_ranges = array();
+
+ $this->_input_encoding = '';
+
+ $this->_dv = array();
+
+ $this->_tmp_dir = $tmp_dir;
+ $this->_tmp_file = '';
+
+ $this->_initialize();
+ }
+
+ /**
+ * Open a tmp file to store the majority of the Worksheet data. If this fails,
+ * for example due to write permissions, store the data in memory. This can be
+ * slow for large files.
+ *
+ * @access private
+ */
+ function _initialize()
+ {
+ if ($this->_using_tmpfile == false) {
+ return;
+ }
+
+ if ($this->_tmp_dir === '' && ini_get('open_basedir') === true) {
+ // open_basedir restriction in effect - store data in memory
+ // ToDo: Let the error actually have an effect somewhere
+ $this->_using_tmpfile = false;
+ return new PEAR_Error('Temp file could not be opened since open_basedir restriction in effect - please use setTmpDir() - using memory storage instead');
+ }
+
+ // Open tmp file for storing Worksheet data
+ if ($this->_tmp_dir === '') {
+ $fh = tmpfile();
+ } else {
+ // For people with open base dir restriction
+ $this->_tmp_file = tempnam($this->_tmp_dir, "Spreadsheet_Excel_Writer");
+ $fh = @fopen($this->_tmp_file, "w+b");
+ }
+
+ if ($fh === false) {
+ // If tmpfile() fails store data in memory
+ $this->_using_tmpfile = false;
+ } else {
+ // Store filehandle
+ $this->_filehandle = $fh;
+ }
+ }
+
+ /**
+ * Add data to the beginning of the workbook (note the reverse order)
+ * and to the end of the workbook.
+ *
+ * @access public
+ * @see Spreadsheet_Excel_Writer_Workbook::storeWorkbook()
+ * @param array $sheetnames The array of sheetnames from the Workbook this
+ * worksheet belongs to
+ */
+ function close($sheetnames)
+ {
+ $num_sheets = count($sheetnames);
+
+ /***********************************************
+ * Prepend in reverse order!!
+ */
+
+ // Prepend the sheet dimensions
+ $this->_storeDimensions();
+
+ // Prepend the sheet password
+ $this->_storePassword();
+
+ // Prepend the sheet protection
+ $this->_storeProtect();
+
+ // Prepend the page setup
+ $this->_storeSetup();
+
+ /* FIXME: margins are actually appended */
+ // Prepend the bottom margin
+ $this->_storeMarginBottom();
+
+ // Prepend the top margin
+ $this->_storeMarginTop();
+
+ // Prepend the right margin
+ $this->_storeMarginRight();
+
+ // Prepend the left margin
+ $this->_storeMarginLeft();
+
+ // Prepend the page vertical centering
+ $this->_storeVcenter();
+
+ // Prepend the page horizontal centering
+ $this->_storeHcenter();
+
+ // Prepend the page footer
+ $this->_storeFooter();
+
+ // Prepend the page header
+ $this->_storeHeader();
+
+ // Prepend the vertical page breaks
+ $this->_storeVbreak();
+
+ // Prepend the horizontal page breaks
+ $this->_storeHbreak();
+
+ // Prepend WSBOOL
+ $this->_storeWsbool();
+
+ // Prepend GRIDSET
+ $this->_storeGridset();
+
+ // Prepend GUTS
+ if ($this->_BIFF_version == 0x0500) {
+ $this->_storeGuts();
+ }
+
+ // Prepend PRINTGRIDLINES
+ $this->_storePrintGridlines();
+
+ // Prepend PRINTHEADERS
+ $this->_storePrintHeaders();
+
+ // Prepend EXTERNSHEET references
+ if ($this->_BIFF_version == 0x0500) {
+ for ($i = $num_sheets; $i > 0; $i--) {
+ $sheetname = $sheetnames[$i-1];
+ $this->_storeExternsheet($sheetname);
+ }
+ }
+
+ // Prepend the EXTERNCOUNT of external references.
+ if ($this->_BIFF_version == 0x0500) {
+ $this->_storeExterncount($num_sheets);
+ }
+
+ // Prepend the COLINFO records if they exist
+ if (!empty($this->_colinfo)) {
+ $colcount = count($this->_colinfo);
+ for ($i = 0; $i < $colcount; $i++) {
+ $this->_storeColinfo($this->_colinfo[$i]);
+ }
+ $this->_storeDefcol();
+ }
+
+ // Prepend the BOF record
+ $this->_storeBof(0x0010);
+
+ /*
+ * End of prepend. Read upwards from here.
+ ***********************************************/
+
+ // Append
+ $this->_storeWindow2();
+ $this->_storeZoom();
+ if (!empty($this->_panes)) {
+ $this->_storePanes($this->_panes);
+ }
+ $this->_storeSelection($this->_selection);
+ $this->_storeMergedCells();
+ /* TODO: add data validity */
+ /*if ($this->_BIFF_version == 0x0600) {
+ $this->_storeDataValidity();
+ }*/
+ $this->_storeEof();
+
+ if ( $this->_tmp_file != '' ) {
+ if ( $this->_filehandle ) {
+ fclose($this->_filehandle);
+ $this->_filehandle = '';
+ }
+ @unlink($this->_tmp_file);
+ $this->_tmp_file = '';
+ $this->_using_tmpfile = true;
+ }
+ }
+
+ /**
+ * Retrieve the worksheet name.
+ * This is usefull when creating worksheets without a name.
+ *
+ * @access public
+ * @return string The worksheet's name
+ */
+ function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Retrieves data from memory in one chunk, or from disk in $buffer
+ * sized chunks.
+ *
+ * @return string The data
+ */
+ function getData()
+ {
+ $buffer = 4096;
+
+ // Return data stored in memory
+ if (isset($this->_data)) {
+ $tmp = $this->_data;
+ unset($this->_data);
+ $fh = $this->_filehandle;
+ if ($this->_using_tmpfile) {
+ fseek($fh, 0);
+ }
+ return $tmp;
+ }
+ // Return data stored on disk
+ if ($this->_using_tmpfile) {
+ if ($tmp = fread($this->_filehandle, $buffer)) {
+ return $tmp;
+ }
+ }
+
+ // No data to return
+ return '';
+ }
+
+ /**
+ * Sets a merged cell range
+ *
+ * @access public
+ * @param integer $first_row First row of the area to merge
+ * @param integer $first_col First column of the area to merge
+ * @param integer $last_row Last row of the area to merge
+ * @param integer $last_col Last column of the area to merge
+ */
+ function setMerge($first_row, $first_col, $last_row, $last_col)
+ {
+ if (($last_row < $first_row) || ($last_col < $first_col)) {
+ return;
+ }
+
+ $max_record_ranges = floor(($this->_limit - 6) / 8);
+ if($this->_merged_cells_counter >= $max_record_ranges)
+ {
+ $this->_merged_cells_record++;
+ $this->_merged_cells_counter = 0;
+ }
+
+ // don't check rowmin, rowmax, etc... because we don't know when this
+ // is going to be called
+ $this->_merged_ranges[$this->_merged_cells_record][] = array($first_row, $first_col, $last_row, $last_col);
+ $this->_merged_cells_counter++;
+ }
+
+ /**
+ * Set this worksheet as a selected worksheet,
+ * i.e. the worksheet has its tab highlighted.
+ *
+ * @access public
+ */
+ function select()
+ {
+ $this->selected = 1;
+ }
+
+ /**
+ * Set this worksheet as the active worksheet,
+ * i.e. the worksheet that is displayed when the workbook is opened.
+ * Also set it as selected.
+ *
+ * @access public
+ */
+ function activate()
+ {
+ $this->selected = 1;
+ $this->activesheet = $this->index;
+ }
+
+ /**
+ * Set this worksheet as the first visible sheet.
+ * This is necessary when there are a large number of worksheets and the
+ * activated worksheet is not visible on the screen.
+ *
+ * @access public
+ */
+ function setFirstSheet()
+ {
+ $this->firstsheet = $this->index;
+ }
+
+ /**
+ * Set the worksheet protection flag
+ * to prevent accidental modification and to
+ * hide formulas if the locked and hidden format properties have been set.
+ *
+ * @access public
+ * @param string $password The password to use for protecting the sheet.
+ */
+ function protect($password)
+ {
+ $this->_protect = 1;
+ $this->_password = $this->_encodePassword($password);
+ }
+
+ /**
+ * Set the width of a single column or a range of columns.
+ *
+ * @access public
+ * @param integer $firstcol first column on the range
+ * @param integer $lastcol last column on the range
+ * @param integer $width width to set
+ * @param mixed $format The optional XF format to apply to the columns
+ * @param integer $hidden The optional hidden atribute
+ * @param integer $level The optional outline level
+ */
+ function setColumn($firstcol, $lastcol, $width, $format = null, $hidden = 0, $level = 0)
+ { // added by Dan Lynn _colinfo as $key => $colinfo)
+ {
+ $existing_start = $colinfo[0]; $existing_end = $colinfo[1];
+ // if the new range starts within another range
+ if ($firstcol > $existing_start && $firstcol < $existing_end)
+ { // trim the existing range to the beginning of the new range
+ $this->_colinfo[$key][1] = $firstcol - 1;
+ // if the new range lies WITHIN the existing range
+ if ($lastcol < $existing_end)
+ { // split the existing range by adding a range after our new range
+ $this->_colinfo[] = array($lastcol+1, $existing_end, $colinfo[2], &$colinfo[3], $colinfo[4], $colinfo[5]);
+ }
+ } // if the new range ends inside an existing range
+ elseif ($lastcol > $existing_start && $lastcol < $existing_end)
+ { // trim the existing range to the end of the new range
+ $this->_colinfo[$key][0] = $lastcol + 1;
+ } // if the new range completely overlaps the existing range
+ elseif ($firstcol <= $existing_start && $lastcol >= $existing_end)
+ {
+ unset($this->_colinfo[$key]);
+ }
+ } // added by Dan Lynn _colinfo = array_values($this->_colinfo);
+ $this->_colinfo[] = array($firstcol, $lastcol, $width, &$format, $hidden, $level);
+ // Set width to zero if column is hidden
+ $width = ($hidden) ? 0 : $width;
+ for ($col = $firstcol; $col <= $lastcol; $col++)
+ {
+ $this->col_sizes[$col] = $width;
+ }
+ }
+
+ /**
+ * Set which cell or cells are selected in a worksheet
+ *
+ * @access public
+ * @param integer $first_row first row in the selected quadrant
+ * @param integer $first_column first column in the selected quadrant
+ * @param integer $last_row last row in the selected quadrant
+ * @param integer $last_column last column in the selected quadrant
+ */
+ function setSelection($first_row,$first_column,$last_row,$last_column)
+ {
+ $this->_selection = array($first_row,$first_column,$last_row,$last_column);
+ }
+
+ /**
+ * Set panes and mark them as frozen.
+ *
+ * @access public
+ * @param array $panes This is the only parameter received and is composed of the following:
+ * 0 => Vertical split position,
+ * 1 => Horizontal split position
+ * 2 => Top row visible
+ * 3 => Leftmost column visible
+ * 4 => Active pane
+ */
+ function freezePanes($panes)
+ {
+ $this->_frozen = 1;
+ $this->_panes = $panes;
+ }
+
+ /**
+ * Set panes and mark them as unfrozen.
+ *
+ * @access public
+ * @param array $panes This is the only parameter received and is composed of the following:
+ * 0 => Vertical split position,
+ * 1 => Horizontal split position
+ * 2 => Top row visible
+ * 3 => Leftmost column visible
+ * 4 => Active pane
+ */
+ function thawPanes($panes)
+ {
+ $this->_frozen = 0;
+ $this->_panes = $panes;
+ }
+
+ /**
+ * Set the page orientation as portrait.
+ *
+ * @access public
+ */
+ function setPortrait()
+ {
+ $this->_orientation = 1;
+ }
+
+ /**
+ * Set the page orientation as landscape.
+ *
+ * @access public
+ */
+ function setLandscape()
+ {
+ $this->_orientation = 0;
+ }
+
+ /**
+ * Set the paper type. Ex. 1 = US Letter, 9 = A4
+ *
+ * @access public
+ * @param integer $size The type of paper size to use
+ */
+ function setPaper($size = 0)
+ {
+ $this->_paper_size = $size;
+ }
+
+
+ /**
+ * Set the page header caption and optional margin.
+ *
+ * @access public
+ * @param string $string The header text
+ * @param float $margin optional head margin in inches.
+ */
+ function setHeader($string,$margin = 0.50)
+ {
+ if (strlen($string) >= 255) {
+ //carp 'Header string must be less than 255 characters';
+ return;
+ }
+ $this->_header = $string;
+ $this->_margin_head = $margin;
+ }
+
+ /**
+ * Set the page footer caption and optional margin.
+ *
+ * @access public
+ * @param string $string The footer text
+ * @param float $margin optional foot margin in inches.
+ */
+ function setFooter($string,$margin = 0.50)
+ {
+ if (strlen($string) >= 255) {
+ //carp 'Footer string must be less than 255 characters';
+ return;
+ }
+ $this->_footer = $string;
+ $this->_margin_foot = $margin;
+ }
+
+ /**
+ * Center the page horinzontally.
+ *
+ * @access public
+ * @param integer $center the optional value for centering. Defaults to 1 (center).
+ */
+ function centerHorizontally($center = 1)
+ {
+ $this->_hcenter = $center;
+ }
+
+ /**
+ * Center the page vertically.
+ *
+ * @access public
+ * @param integer $center the optional value for centering. Defaults to 1 (center).
+ */
+ function centerVertically($center = 1)
+ {
+ $this->_vcenter = $center;
+ }
+
+ /**
+ * Set all the page margins to the same value in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMargins($margin)
+ {
+ $this->setMarginLeft($margin);
+ $this->setMarginRight($margin);
+ $this->setMarginTop($margin);
+ $this->setMarginBottom($margin);
+ }
+
+ /**
+ * Set the left and right margins to the same value in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMargins_LR($margin)
+ {
+ $this->setMarginLeft($margin);
+ $this->setMarginRight($margin);
+ }
+
+ /**
+ * Set the top and bottom margins to the same value in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMargins_TB($margin)
+ {
+ $this->setMarginTop($margin);
+ $this->setMarginBottom($margin);
+ }
+
+ /**
+ * Set the left margin in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMarginLeft($margin = 0.75)
+ {
+ $this->_margin_left = $margin;
+ }
+
+ /**
+ * Set the right margin in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMarginRight($margin = 0.75)
+ {
+ $this->_margin_right = $margin;
+ }
+
+ /**
+ * Set the top margin in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMarginTop($margin = 1.00)
+ {
+ $this->_margin_top = $margin;
+ }
+
+ /**
+ * Set the bottom margin in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMarginBottom($margin = 1.00)
+ {
+ $this->_margin_bottom = $margin;
+ }
+
+ /**
+ * Set the rows to repeat at the top of each printed page.
+ *
+ * @access public
+ * @param integer $first_row First row to repeat
+ * @param integer $last_row Last row to repeat. Optional.
+ */
+ function repeatRows($first_row, $last_row = null)
+ {
+ $this->title_rowmin = $first_row;
+ if (isset($last_row)) { //Second row is optional
+ $this->title_rowmax = $last_row;
+ } else {
+ $this->title_rowmax = $first_row;
+ }
+ }
+
+ /**
+ * Set the columns to repeat at the left hand side of each printed page.
+ *
+ * @access public
+ * @param integer $first_col First column to repeat
+ * @param integer $last_col Last column to repeat. Optional.
+ */
+ function repeatColumns($first_col, $last_col = null)
+ {
+ $this->title_colmin = $first_col;
+ if (isset($last_col)) { // Second col is optional
+ $this->title_colmax = $last_col;
+ } else {
+ $this->title_colmax = $first_col;
+ }
+ }
+
+ /**
+ * Set the area of each worksheet that will be printed.
+ *
+ * @access public
+ * @param integer $first_row First row of the area to print
+ * @param integer $first_col First column of the area to print
+ * @param integer $last_row Last row of the area to print
+ * @param integer $last_col Last column of the area to print
+ */
+ function printArea($first_row, $first_col, $last_row, $last_col)
+ {
+ $this->print_rowmin = $first_row;
+ $this->print_colmin = $first_col;
+ $this->print_rowmax = $last_row;
+ $this->print_colmax = $last_col;
+ }
+
+
+ /**
+ * Set the option to hide gridlines on the printed page.
+ *
+ * @access public
+ */
+ function hideGridlines()
+ {
+ $this->_print_gridlines = 0;
+ }
+
+ /**
+ * Set the option to hide gridlines on the worksheet (as seen on the screen).
+ *
+ * @access public
+ */
+ function hideScreenGridlines()
+ {
+ $this->_screen_gridlines = 0;
+ }
+
+ /**
+ * Set the option to print the row and column headers on the printed page.
+ *
+ * @access public
+ * @param integer $print Whether to print the headers or not. Defaults to 1 (print).
+ */
+ function printRowColHeaders($print = 1)
+ {
+ $this->_print_headers = $print;
+ }
+
+ /**
+ * Set the vertical and horizontal number of pages that will define the maximum area printed.
+ * It doesn't seem to work with OpenOffice.
+ *
+ * @access public
+ * @param integer $width Maximun width of printed area in pages
+ * @param integer $height Maximun heigth of printed area in pages
+ * @see setPrintScale()
+ */
+ function fitToPages($width, $height)
+ {
+ $this->_fit_page = 1;
+ $this->_fit_width = $width;
+ $this->_fit_height = $height;
+ }
+
+ /**
+ * Store the horizontal page breaks on a worksheet (for printing).
+ * The breaks represent the row after which the break is inserted.
+ *
+ * @access public
+ * @param array $breaks Array containing the horizontal page breaks
+ */
+ function setHPagebreaks($breaks)
+ {
+ foreach ($breaks as $break) {
+ array_push($this->_hbreaks, $break);
+ }
+ }
+
+ /**
+ * Store the vertical page breaks on a worksheet (for printing).
+ * The breaks represent the column after which the break is inserted.
+ *
+ * @access public
+ * @param array $breaks Array containing the vertical page breaks
+ */
+ function setVPagebreaks($breaks)
+ {
+ foreach ($breaks as $break) {
+ array_push($this->_vbreaks, $break);
+ }
+ }
+
+
+ /**
+ * Set the worksheet zoom factor.
+ *
+ * @access public
+ * @param integer $scale The zoom factor
+ */
+ function setZoom($scale = 100)
+ {
+ // Confine the scale to Excel's range
+ if ($scale < 10 || $scale > 400) {
+ $this->raiseError("Zoom factor $scale outside range: 10 <= zoom <= 400");
+ $scale = 100;
+ }
+
+ $this->_zoom = floor($scale);
+ }
+
+ /**
+ * Set the scale factor for the printed page.
+ * It turns off the "fit to page" option
+ *
+ * @access public
+ * @param integer $scale The optional scale factor. Defaults to 100
+ */
+ function setPrintScale($scale = 100)
+ {
+ // Confine the scale to Excel's range
+ if ($scale < 10 || $scale > 400) {
+ $this->raiseError("Print scale $scale outside range: 10 <= zoom <= 400");
+ $scale = 100;
+ }
+
+ // Turn off "fit to page" option
+ $this->_fit_page = 0;
+
+ $this->_print_scale = floor($scale);
+ }
+
+ /**
+ * Map to the appropriate write method acording to the token recieved.
+ *
+ * @access public
+ * @param integer $row The row of the cell we are writing to
+ * @param integer $col The column of the cell we are writing to
+ * @param mixed $token What we are writing
+ * @param mixed $format The optional format to apply to the cell
+ */
+ function write($row, $col, $token, $format = null)
+ {
+ // Check for a cell reference in A1 notation and substitute row and column
+ /*if ($_[0] =~ /^\D/) {
+ @_ = $this->_substituteCellref(@_);
+ }*/
+
+ if (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/", $token)) {
+ // Match number
+ return $this->writeNumber($row, $col, $token, $format);
+ } elseif (preg_match("/^[fh]tt?p:\/\//", $token)) {
+ // Match http or ftp URL
+ return $this->writeUrl($row, $col, $token, '', $format);
+ } elseif (preg_match("/^mailto:/", $token)) {
+ // Match mailto:
+ return $this->writeUrl($row, $col, $token, '', $format);
+ } elseif (preg_match("/^(?:in|ex)ternal:/", $token)) {
+ // Match internal or external sheet link
+ return $this->writeUrl($row, $col, $token, '', $format);
+ } elseif (preg_match("/^=/", $token)) {
+ // Match formula
+ return $this->writeFormula($row, $col, $token, $format);
+ } elseif ($token == '') {
+ // Match blank
+ return $this->writeBlank($row, $col, $format);
+ } else {
+ // Default: match string
+ return $this->writeString($row, $col, $token, $format);
+ }
+ }
+
+ /**
+ * Write an array of values as a row
+ *
+ * @access public
+ * @param integer $row The row we are writing to
+ * @param integer $col The first col (leftmost col) we are writing to
+ * @param array $val The array of values to write
+ * @param mixed $format The optional format to apply to the cell
+ * @return mixed PEAR_Error on failure
+ */
+
+ function writeRow($row, $col, $val, $format = null)
+ {
+ $retval = '';
+ if (is_array($val)) {
+ foreach ($val as $v) {
+ if (is_array($v)) {
+ $this->writeCol($row, $col, $v, $format);
+ } else {
+ $this->write($row, $col, $v, $format);
+ }
+ $col++;
+ }
+ } else {
+ $retval = new PEAR_Error('$val needs to be an array');
+ }
+ return($retval);
+ }
+
+ /**
+ * Write an array of values as a column
+ *
+ * @access public
+ * @param integer $row The first row (uppermost row) we are writing to
+ * @param integer $col The col we are writing to
+ * @param array $val The array of values to write
+ * @param mixed $format The optional format to apply to the cell
+ * @return mixed PEAR_Error on failure
+ */
+
+ function writeCol($row, $col, $val, $format = null)
+ {
+ $retval = '';
+ if (is_array($val)) {
+ foreach ($val as $v) {
+ $this->write($row, $col, $v, $format);
+ $row++;
+ }
+ } else {
+ $retval = new PEAR_Error('$val needs to be an array');
+ }
+ return($retval);
+ }
+
+ /**
+ * Returns an index to the XF record in the workbook
+ *
+ * @access private
+ * @param mixed &$format The optional XF format
+ * @return integer The XF record index
+ */
+ function _XF(&$format)
+ {
+ if ($format) {
+ return($format->getXfIndex());
+ } else {
+ return(0x0F);
+ }
+ }
+
+
+ /******************************************************************************
+ *******************************************************************************
+ *
+ * Internal methods
+ */
+
+
+ /**
+ * Store Worksheet data in memory using the parent's class append() or to a
+ * temporary file, the default.
+ *
+ * @access private
+ * @param string $data The binary data to append
+ */
+ function _append($data)
+ {
+ if ($this->_using_tmpfile) {
+ // Add CONTINUE records if necessary
+ if (strlen($data) > $this->_limit) {
+ $data = $this->_addContinue($data);
+ }
+ fwrite($this->_filehandle, $data);
+ $this->_datasize += strlen($data);
+ } else {
+ parent::_append($data);
+ }
+ }
+
+ /**
+ * Substitute an Excel cell reference in A1 notation for zero based row and
+ * column values in an argument list.
+ *
+ * Ex: ("A4", "Hello") is converted to (3, 0, "Hello").
+ *
+ * @access private
+ * @param string $cell The cell reference. Or range of cells.
+ * @return array
+ */
+ function _substituteCellref($cell)
+ {
+ $cell = strtoupper($cell);
+
+ // Convert a column range: 'A:A' or 'B:G'
+ if (preg_match("/([A-I]?[A-Z]):([A-I]?[A-Z])/", $cell, $match)) {
+ list($no_use, $col1) = $this->_cellToRowcol($match[1] .'1'); // Add a dummy row
+ list($no_use, $col2) = $this->_cellToRowcol($match[2] .'1'); // Add a dummy row
+ return(array($col1, $col2));
+ }
+
+ // Convert a cell range: 'A1:B7'
+ if (preg_match("/\$?([A-I]?[A-Z]\$?\d+):\$?([A-I]?[A-Z]\$?\d+)/", $cell, $match)) {
+ list($row1, $col1) = $this->_cellToRowcol($match[1]);
+ list($row2, $col2) = $this->_cellToRowcol($match[2]);
+ return(array($row1, $col1, $row2, $col2));
+ }
+
+ // Convert a cell reference: 'A1' or 'AD2000'
+ if (preg_match("/\$?([A-I]?[A-Z]\$?\d+)/", $cell)) {
+ list($row1, $col1) = $this->_cellToRowcol($match[1]);
+ return(array($row1, $col1));
+ }
+
+ // TODO use real error codes
+ $this->raiseError("Unknown cell reference $cell", 0, PEAR_ERROR_DIE);
+ }
+
+ /**
+ * Convert an Excel cell reference in A1 notation to a zero based row and column
+ * reference; converts C1 to (0, 2).
+ *
+ * @access private
+ * @param string $cell The cell reference.
+ * @return array containing (row, column)
+ */
+ function _cellToRowcol($cell)
+ {
+ preg_match("/\$?([A-I]?[A-Z])\$?(\d+)/",$cell,$match);
+ $col = $match[1];
+ $row = $match[2];
+
+ // Convert base26 column string to number
+ $chars = explode('', $col);
+ $expn = 0;
+ $col = 0;
+
+ while ($chars) {
+ $char = array_pop($chars); // LS char first
+ $col += (ord($char) -ord('A') +1) * pow(26,$expn);
+ $expn++;
+ }
+
+ // Convert 1-index to zero-index
+ $row--;
+ $col--;
+
+ return(array($row, $col));
+ }
+
+ /**
+ * Based on the algorithm provided by Daniel Rentz of OpenOffice.
+ *
+ * @access private
+ * @param string $plaintext The password to be encoded in plaintext.
+ * @return string The encoded password
+ */
+ function _encodePassword($plaintext)
+ {
+ $password = 0x0000;
+ $i = 1; // char position
+
+ // split the plain text password in its component characters
+ $chars = preg_split('//', $plaintext, -1, PREG_SPLIT_NO_EMPTY);
+ foreach ($chars as $char) {
+ $value = ord($char) << $i; // shifted ASCII value
+ $rotated_bits = $value >> 15; // rotated bits beyond bit 15
+ $value &= 0x7fff; // first 15 bits
+ $password ^= ($value | $rotated_bits);
+ $i++;
+ }
+
+ $password ^= strlen($plaintext);
+ $password ^= 0xCE4B;
+
+ return($password);
+ }
+
+ /**
+ * This method sets the properties for outlining and grouping. The defaults
+ * correspond to Excel's defaults.
+ *
+ * @param bool $visible
+ * @param bool $symbols_below
+ * @param bool $symbols_right
+ * @param bool $auto_style
+ */
+ function setOutline($visible = true, $symbols_below = true, $symbols_right = true, $auto_style = false)
+ {
+ $this->_outline_on = $visible;
+ $this->_outline_below = $symbols_below;
+ $this->_outline_right = $symbols_right;
+ $this->_outline_style = $auto_style;
+
+ // Ensure this is a boolean vale for Window2
+ if ($this->_outline_on) {
+ $this->_outline_on = 1;
+ }
+ }
+
+ /**
+ * This method sets the worksheet direction to right-to-left (RTL)
+ *
+ * @param bool $rtl
+ */
+ function setRTL($rtl = true)
+ {
+ $this->_Arabic = ($rtl ? 1 : 0);
+ }
+
+ /******************************************************************************
+ *******************************************************************************
+ *
+ * BIFF RECORDS
+ */
+
+
+ /**
+ * Write a double to the specified row and column (zero indexed).
+ * An integer can be written as a double. Excel will display an
+ * integer. $format is optional.
+ *
+ * Returns 0 : normal termination
+ * -2 : row or column out of range
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param float $num The number to write
+ * @param mixed $format The optional XF format
+ * @return integer
+ */
+ function writeNumber($row, $col, $num, $format = null)
+ {
+ $record = 0x0203; // Record identifier
+ $length = 0x000E; // Number of bytes to follow
+
+ $xf = $this->_XF($format); // The cell format
+
+ // Check that row and col are valid and store max and min values
+ if ($row >= $this->_xls_rowmax) {
+ return(-2);
+ }
+ if ($col >= $this->_xls_colmax) {
+ return(-2);
+ }
+ if ($row < $this->_dim_rowmin) {
+ $this->_dim_rowmin = $row;
+ }
+ if ($row > $this->_dim_rowmax) {
+ $this->_dim_rowmax = $row;
+ }
+ if ($col < $this->_dim_colmin) {
+ $this->_dim_colmin = $col;
+ }
+ if ($col > $this->_dim_colmax) {
+ $this->_dim_colmax = $col;
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvv", $row, $col, $xf);
+ $xl_double = pack("d", $num);
+ if ($this->_byte_order) { // if it's Big Endian
+ $xl_double = strrev($xl_double);
+ }
+
+ $this->_append($header.$data.$xl_double);
+ return(0);
+ }
+
+ /**
+ * Write a string to the specified row and column (zero indexed).
+ * NOTE: there is an Excel 5 defined limit of 255 characters.
+ * $format is optional.
+ * Returns 0 : normal termination
+ * -2 : row or column out of range
+ * -3 : long string truncated to 255 chars
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param string $str The string to write
+ * @param mixed $format The XF format for the cell
+ * @return integer
+ */
+ function writeString($row, $col, $str, $format = null)
+ {
+ if ($this->_BIFF_version == 0x0600) {
+ return $this->writeStringBIFF8($row, $col, $str, $format);
+ }
+ $strlen = strlen($str);
+ $record = 0x0204; // Record identifier
+ $length = 0x0008 + $strlen; // Bytes to follow
+ $xf = $this->_XF($format); // The cell format
+
+ $str_error = 0;
+
+ // Check that row and col are valid and store max and min values
+ if ($row >= $this->_xls_rowmax) {
+ return(-2);
+ }
+ if ($col >= $this->_xls_colmax) {
+ return(-2);
+ }
+ if ($row < $this->_dim_rowmin) {
+ $this->_dim_rowmin = $row;
+ }
+ if ($row > $this->_dim_rowmax) {
+ $this->_dim_rowmax = $row;
+ }
+ if ($col < $this->_dim_colmin) {
+ $this->_dim_colmin = $col;
+ }
+ if ($col > $this->_dim_colmax) {
+ $this->_dim_colmax = $col;
+ }
+
+ if ($strlen > $this->_xls_strmax) { // LABEL must be < 255 chars
+ $str = substr($str, 0, $this->_xls_strmax);
+ $length = 0x0008 + $this->_xls_strmax;
+ $strlen = $this->_xls_strmax;
+ $str_error = -3;
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvv", $row, $col, $xf, $strlen);
+ $this->_append($header . $data . $str);
+ return($str_error);
+ }
+
+ /**
+ * Sets Input Encoding for writing strings
+ *
+ * @access public
+ * @param string $encoding The encoding. Ex: 'UTF-16LE', 'utf-8', 'ISO-859-7'
+ */
+ function setInputEncoding($encoding)
+ {
+ if ($encoding != 'UTF-16LE' && !function_exists('iconv')) {
+ $this->raiseError("Using an input encoding other than UTF-16LE requires PHP support for iconv");
+ }
+ $this->_input_encoding = $encoding;
+ }
+
+ /**
+ * Write a string to the specified row and column (zero indexed).
+ * This is the BIFF8 version (no 255 chars limit).
+ * $format is optional.
+ * Returns 0 : normal termination
+ * -2 : row or column out of range
+ * -3 : long string truncated to 255 chars
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param string $str The string to write
+ * @param mixed $format The XF format for the cell
+ * @return integer
+ */
+ function writeStringBIFF8($row, $col, $str, $format = null)
+ {
+ if ($this->_input_encoding == 'UTF-16LE')
+ {
+ $strlen = function_exists('mb_strlen') ? mb_strlen($str, 'UTF-16LE') : (strlen($str) / 2);
+ $encoding = 0x1;
+ }
+ elseif ($this->_input_encoding != '')
+ {
+ $str = iconv($this->_input_encoding, 'UTF-16LE', $str);
+ $strlen = function_exists('mb_strlen') ? mb_strlen($str, 'UTF-16LE') : (strlen($str) / 2);
+ $encoding = 0x1;
+ }
+ else
+ {
+ $strlen = strlen($str);
+ $encoding = 0x0;
+ }
+ $record = 0x00FD; // Record identifier
+ $length = 0x000A; // Bytes to follow
+ $xf = $this->_XF($format); // The cell format
+
+ $str_error = 0;
+
+ // Check that row and col are valid and store max and min values
+ if ($this->_checkRowCol($row, $col) == false) {
+ return -2;
+ }
+
+ $str = pack('vC', $strlen, $encoding).$str;
+
+ /* check if string is already present */
+ if (!isset($this->_str_table[$str])) {
+ $this->_str_table[$str] = $this->_str_unique++;
+ }
+ $this->_str_total++;
+
+ $header = pack('vv', $record, $length);
+ $data = pack('vvvV', $row, $col, $xf, $this->_str_table[$str]);
+ $this->_append($header.$data);
+ return $str_error;
+ }
+
+ /**
+ * Check row and col before writing to a cell, and update the sheet's
+ * dimensions accordingly
+ *
+ * @access private
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @return boolean true for success, false if row and/or col are grester
+ * then maximums allowed.
+ */
+ function _checkRowCol($row, $col)
+ {
+ if ($row >= $this->_xls_rowmax) {
+ return false;
+ }
+ if ($col >= $this->_xls_colmax) {
+ return false;
+ }
+ if ($row < $this->_dim_rowmin) {
+ $this->_dim_rowmin = $row;
+ }
+ if ($row > $this->_dim_rowmax) {
+ $this->_dim_rowmax = $row;
+ }
+ if ($col < $this->_dim_colmin) {
+ $this->_dim_colmin = $col;
+ }
+ if ($col > $this->_dim_colmax) {
+ $this->_dim_colmax = $col;
+ }
+ return true;
+ }
+
+ /**
+ * Writes a note associated with the cell given by the row and column.
+ * NOTE records don't have a length limit.
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param string $note The note to write
+ */
+ function writeNote($row, $col, $note)
+ {
+ $note_length = strlen($note);
+ $record = 0x001C; // Record identifier
+ $max_length = 2048; // Maximun length for a NOTE record
+ //$length = 0x0006 + $note_length; // Bytes to follow
+
+ // Check that row and col are valid and store max and min values
+ if ($row >= $this->_xls_rowmax) {
+ return(-2);
+ }
+ if ($col >= $this->_xls_colmax) {
+ return(-2);
+ }
+ if ($row < $this->_dim_rowmin) {
+ $this->_dim_rowmin = $row;
+ }
+ if ($row > $this->_dim_rowmax) {
+ $this->_dim_rowmax = $row;
+ }
+ if ($col < $this->_dim_colmin) {
+ $this->_dim_colmin = $col;
+ }
+ if ($col > $this->_dim_colmax) {
+ $this->_dim_colmax = $col;
+ }
+
+ // Length for this record is no more than 2048 + 6
+ $length = 0x0006 + min($note_length, 2048);
+ $header = pack("vv", $record, $length);
+ $data = pack("vvv", $row, $col, $note_length);
+ $this->_append($header . $data . substr($note, 0, 2048));
+
+ for ($i = $max_length; $i < $note_length; $i += $max_length) {
+ $chunk = substr($note, $i, $max_length);
+ $length = 0x0006 + strlen($chunk);
+ $header = pack("vv", $record, $length);
+ $data = pack("vvv", -1, 0, strlen($chunk));
+ $this->_append($header.$data.$chunk);
+ }
+ return(0);
+ }
+
+ /**
+ * Write a blank cell to the specified row and column (zero indexed).
+ * A blank cell is used to specify formatting without adding a string
+ * or a number.
+ *
+ * A blank cell without a format serves no purpose. Therefore, we don't write
+ * a BLANK record unless a format is specified.
+ *
+ * Returns 0 : normal termination (including no format)
+ * -1 : insufficient number of arguments
+ * -2 : row or column out of range
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param mixed $format The XF format
+ */
+ function writeBlank($row, $col, $format)
+ {
+ // Don't write a blank cell unless it has a format
+ if (!$format) {
+ return(0);
+ }
+
+ $record = 0x0201; // Record identifier
+ $length = 0x0006; // Number of bytes to follow
+ $xf = $this->_XF($format); // The cell format
+
+ // Check that row and col are valid and store max and min values
+ if ($row >= $this->_xls_rowmax) {
+ return(-2);
+ }
+ if ($col >= $this->_xls_colmax) {
+ return(-2);
+ }
+ if ($row < $this->_dim_rowmin) {
+ $this->_dim_rowmin = $row;
+ }
+ if ($row > $this->_dim_rowmax) {
+ $this->_dim_rowmax = $row;
+ }
+ if ($col < $this->_dim_colmin) {
+ $this->_dim_colmin = $col;
+ }
+ if ($col > $this->_dim_colmax) {
+ $this->_dim_colmax = $col;
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvv", $row, $col, $xf);
+ $this->_append($header . $data);
+ return 0;
+ }
+
+ /**
+ * Write a formula to the specified row and column (zero indexed).
+ * The textual representation of the formula is passed to the parser in
+ * Parser.php which returns a packed binary string.
+ *
+ * Returns 0 : normal termination
+ * -1 : formula errors (bad formula)
+ * -2 : row or column out of range
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param string $formula The formula text string
+ * @param mixed $format The optional XF format
+ * @return integer
+ */
+ function writeFormula($row, $col, $formula, $format = null)
+ {
+ $record = 0x0006; // Record identifier
+
+ // Excel normally stores the last calculated value of the formula in $num.
+ // Clearly we are not in a position to calculate this a priori. Instead
+ // we set $num to zero and set the option flags in $grbit to ensure
+ // automatic calculation of the formula when the file is opened.
+ //
+ $xf = $this->_XF($format); // The cell format
+ $num = 0x00; // Current value of formula
+ $grbit = 0x03; // Option flags
+ $unknown = 0x0000; // Must be zero
+
+
+ // Check that row and col are valid and store max and min values
+ if ($this->_checkRowCol($row, $col) == false) {
+ return -2;
+ }
+
+ // Strip the '=' or '@' sign at the beginning of the formula string
+ if (preg_match("/^=/", $formula)) {
+ $formula = preg_replace("/(^=)/", "", $formula);
+ } elseif (preg_match("/^@/", $formula)) {
+ $formula = preg_replace("/(^@)/", "", $formula);
+ } else {
+ // Error handling
+ $this->writeString($row, $col, 'Unrecognised character for formula');
+ return -1;
+ }
+
+ // Parse the formula using the parser in Parser.php
+ $error = $this->_parser->parse($formula);
+ if ($this->isError($error)) {
+ $this->writeString($row, $col, $error->getMessage());
+ return -1;
+ }
+
+ $formula = $this->_parser->toReversePolish();
+ if ($this->isError($formula)) {
+ $this->writeString($row, $col, $formula->getMessage());
+ return -1;
+ }
+
+ $formlen = strlen($formula); // Length of the binary string
+ $length = 0x16 + $formlen; // Length of the record data
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvdvVv", $row, $col, $xf, $num,
+ $grbit, $unknown, $formlen);
+
+ $this->_append($header . $data . $formula);
+ return 0;
+ }
+
+ /**
+ * Write a hyperlink.
+ * This is comprised of two elements: the visible label and
+ * the invisible link. The visible label is the same as the link unless an
+ * alternative string is specified. The label is written using the
+ * writeString() method. Therefore the 255 characters string limit applies.
+ * $string and $format are optional.
+ *
+ * The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external
+ * directory url.
+ *
+ * Returns 0 : normal termination
+ * -2 : row or column out of range
+ * -3 : long string truncated to 255 chars
+ *
+ * @access public
+ * @param integer $row Row
+ * @param integer $col Column
+ * @param string $url URL string
+ * @param string $string Alternative label
+ * @param mixed $format The cell format
+ * @return integer
+ */
+ function writeUrl($row, $col, $url, $string = '', $format = null)
+ {
+ // Add start row and col to arg list
+ return($this->_writeUrlRange($row, $col, $row, $col, $url, $string, $format));
+ }
+
+ /**
+ * This is the more general form of writeUrl(). It allows a hyperlink to be
+ * written to a range of cells. This function also decides the type of hyperlink
+ * to be written. These are either, Web (http, ftp, mailto), Internal
+ * (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1').
+ *
+ * @access private
+ * @see writeUrl()
+ * @param integer $row1 Start row
+ * @param integer $col1 Start column
+ * @param integer $row2 End row
+ * @param integer $col2 End column
+ * @param string $url URL string
+ * @param string $string Alternative label
+ * @param mixed $format The cell format
+ * @return integer
+ */
+
+ function _writeUrlRange($row1, $col1, $row2, $col2, $url, $string = '', $format = null)
+ {
+
+ // Check for internal/external sheet links or default to web link
+ if (preg_match('[^internal:]', $url)) {
+ return($this->_writeUrlInternal($row1, $col1, $row2, $col2, $url, $string, $format));
+ }
+ if (preg_match('[^external:]', $url)) {
+ return($this->_writeUrlExternal($row1, $col1, $row2, $col2, $url, $string, $format));
+ }
+ return($this->_writeUrlWeb($row1, $col1, $row2, $col2, $url, $string, $format));
+ }
+
+
+ /**
+ * Used to write http, ftp and mailto hyperlinks.
+ * The link type ($options) is 0x03 is the same as absolute dir ref without
+ * sheet. However it is differentiated by the $unknown2 data stream.
+ *
+ * @access private
+ * @see writeUrl()
+ * @param integer $row1 Start row
+ * @param integer $col1 Start column
+ * @param integer $row2 End row
+ * @param integer $col2 End column
+ * @param string $url URL string
+ * @param string $str Alternative label
+ * @param mixed $format The cell format
+ * @return integer
+ */
+ function _writeUrlWeb($row1, $col1, $row2, $col2, $url, $str, $format = null)
+ {
+ $record = 0x01B8; // Record identifier
+ $length = 0x00000; // Bytes to follow
+
+ if (!$format) {
+ $format = $this->_url_format;
+ }
+
+ // Write the visible label using the writeString() method.
+ if ($str == '') {
+ $str = $url;
+ }
+ $str_error = is_numeric($str) ? $this->writeNumber($row1, $col1, $str, $format) : $this->writeString($row1, $col1, $str, $format);
+ if (($str_error == -2) || ($str_error == -3)) {
+ return $str_error;
+ }
+
+ // Pack the undocumented parts of the hyperlink stream
+ $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000");
+ $unknown2 = pack("H*", "E0C9EA79F9BACE118C8200AA004BA90B");
+
+ // Pack the option flags
+ $options = pack("V", 0x03);
+
+ // Convert URL to a null terminated wchar string
+ $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY));
+ $url = $url . "\0\0\0";
+
+ // Pack the length of the URL
+ $url_len = pack("V", strlen($url));
+
+ // Calculate the data length
+ $length = 0x34 + strlen($url);
+
+ // Pack the header data
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvv", $row1, $row2, $col1, $col2);
+
+ // Write the packed data
+ $this->_append($header . $data .
+ $unknown1 . $options .
+ $unknown2 . $url_len . $url);
+ return($str_error);
+ }
+
+ /**
+ * Used to write internal reference hyperlinks such as "Sheet1!A1".
+ *
+ * @access private
+ * @see writeUrl()
+ * @param integer $row1 Start row
+ * @param integer $col1 Start column
+ * @param integer $row2 End row
+ * @param integer $col2 End column
+ * @param string $url URL string
+ * @param string $str Alternative label
+ * @param mixed $format The cell format
+ * @return integer
+ */
+ function _writeUrlInternal($row1, $col1, $row2, $col2, $url, $str, $format = null)
+ {
+ $record = 0x01B8; // Record identifier
+ $length = 0x00000; // Bytes to follow
+
+ if (!$format) {
+ $format = $this->_url_format;
+ }
+
+ // Strip URL type
+ $url = preg_replace('/^internal:/', '', $url);
+
+ // Write the visible label
+ if ($str == '') {
+ $str = $url;
+ }
+ $str_error = is_numeric($str) ? $this->writeNumber($row1, $col1, $str, $format) : $this->writeString($row1, $col1, $str, $format);
+ if (($str_error == -2) || ($str_error == -3)) {
+ return $str_error;
+ }
+
+ // Pack the undocumented parts of the hyperlink stream
+ $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000");
+
+ // Pack the option flags
+ $options = pack("V", 0x08);
+
+ // Convert the URL type and to a null terminated wchar string
+ $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY));
+ $url = $url . "\0\0\0";
+
+ // Pack the length of the URL as chars (not wchars)
+ $url_len = pack("V", floor(strlen($url)/2));
+
+ // Calculate the data length
+ $length = 0x24 + strlen($url);
+
+ // Pack the header data
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvv", $row1, $row2, $col1, $col2);
+
+ // Write the packed data
+ $this->_append($header . $data .
+ $unknown1 . $options .
+ $url_len . $url);
+ return($str_error);
+ }
+
+ /**
+ * Write links to external directory names such as 'c:\foo.xls',
+ * c:\foo.xls#Sheet1!A1', '../../foo.xls'. and '../../foo.xls#Sheet1!A1'.
+ *
+ * Note: Excel writes some relative links with the $dir_long string. We ignore
+ * these cases for the sake of simpler code.
+ *
+ * @access private
+ * @see writeUrl()
+ * @param integer $row1 Start row
+ * @param integer $col1 Start column
+ * @param integer $row2 End row
+ * @param integer $col2 End column
+ * @param string $url URL string
+ * @param string $str Alternative label
+ * @param mixed $format The cell format
+ * @return integer
+ */
+ function _writeUrlExternal($row1, $col1, $row2, $col2, $url, $str, $format = null)
+ {
+ // Network drives are different. We will handle them separately
+ // MS/Novell network drives and shares start with \\
+ if (preg_match('[^external:\\\\]', $url)) {
+ return; //($this->_writeUrlExternal_net($row1, $col1, $row2, $col2, $url, $str, $format));
+ }
+
+ $record = 0x01B8; // Record identifier
+ $length = 0x00000; // Bytes to follow
+
+ if (!$format) {
+ $format = $this->_url_format;
+ }
+
+ // Strip URL type and change Unix dir separator to Dos style (if needed)
+ //
+ $url = preg_replace('/^external:/', '', $url);
+ $url = preg_replace('/\//', "\\", $url);
+
+ // Write the visible label
+ if ($str == '') {
+ $str = preg_replace('/\#/', ' - ', $url);
+ }
+ $str_error = is_numeric($str) ? $this->writeNumber($row1, $col1, $str, $format) : $this->writeString($row1, $col1, $str, $format);
+ if (($str_error == -2) or ($str_error == -3)) {
+ return $str_error;
+ }
+
+ // Determine if the link is relative or absolute:
+ // relative if link contains no dir separator, "somefile.xls"
+ // relative if link starts with up-dir, "..\..\somefile.xls"
+ // otherwise, absolute
+
+ $absolute = 0x02; // Bit mask
+ if (!preg_match("/\\\/", $url)) {
+ $absolute = 0x00;
+ }
+ if (preg_match("/^\.\.\\\/", $url)) {
+ $absolute = 0x00;
+ }
+ $link_type = 0x01 | $absolute;
+
+ // Determine if the link contains a sheet reference and change some of the
+ // parameters accordingly.
+ // Split the dir name and sheet name (if it exists)
+ /*if (preg_match("/\#/", $url)) {
+ list($dir_long, $sheet) = split("\#", $url);
+ } else {
+ $dir_long = $url;
+ }
+
+ if (isset($sheet)) {
+ $link_type |= 0x08;
+ $sheet_len = pack("V", strlen($sheet) + 0x01);
+ $sheet = join("\0", split('', $sheet));
+ $sheet .= "\0\0\0";
+ } else {
+ $sheet_len = '';
+ $sheet = '';
+ }*/
+ $dir_long = $url;
+ if (preg_match("/\#/", $url)) {
+ $link_type |= 0x08;
+ }
+
+
+
+ // Pack the link type
+ $link_type = pack("V", $link_type);
+
+ // Calculate the up-level dir count e.g.. (..\..\..\ == 3)
+ $up_count = preg_match_all("/\.\.\\\/", $dir_long, $useless);
+ $up_count = pack("v", $up_count);
+
+ // Store the short dos dir name (null terminated)
+ $dir_short = preg_replace("/\.\.\\\/", '', $dir_long) . "\0";
+
+ // Store the long dir name as a wchar string (non-null terminated)
+ //$dir_long = join("\0", split('', $dir_long));
+ $dir_long = $dir_long . "\0";
+
+ // Pack the lengths of the dir strings
+ $dir_short_len = pack("V", strlen($dir_short) );
+ $dir_long_len = pack("V", strlen($dir_long) );
+ $stream_len = pack("V", 0);//strlen($dir_long) + 0x06);
+
+ // Pack the undocumented parts of the hyperlink stream
+ $unknown1 = pack("H*",'D0C9EA79F9BACE118C8200AA004BA90B02000000' );
+ $unknown2 = pack("H*",'0303000000000000C000000000000046' );
+ $unknown3 = pack("H*",'FFFFADDE000000000000000000000000000000000000000');
+ $unknown4 = pack("v", 0x03 );
+
+ // Pack the main data stream
+ $data = pack("vvvv", $row1, $row2, $col1, $col2) .
+ $unknown1 .
+ $link_type .
+ $unknown2 .
+ $up_count .
+ $dir_short_len.
+ $dir_short .
+ $unknown3 .
+ $stream_len ;/*.
+ $dir_long_len .
+ $unknown4 .
+ $dir_long .
+ $sheet_len .
+ $sheet ;*/
+
+ // Pack the header data
+ $length = strlen($data);
+ $header = pack("vv", $record, $length);
+
+ // Write the packed data
+ $this->_append($header. $data);
+ return($str_error);
+ }
+
+
+ /**
+ * This method is used to set the height and format for a row.
+ *
+ * @access public
+ * @param integer $row The row to set
+ * @param integer $height Height we are giving to the row.
+ * Use null to set XF without setting height
+ * @param mixed $format XF format we are giving to the row
+ * @param bool $hidden The optional hidden attribute
+ * @param integer $level The optional outline level for row, in range [0,7]
+ */
+ function setRow($row, $height, $format = null, $hidden = false, $level = 0)
+ {
+ $record = 0x0208; // Record identifier
+ $length = 0x0010; // Number of bytes to follow
+
+ $colMic = 0x0000; // First defined column
+ $colMac = 0x0000; // Last defined column
+ $irwMac = 0x0000; // Used by Excel to optimise loading
+ $reserved = 0x0000; // Reserved
+ $grbit = 0x0000; // Option flags
+ $ixfe = $this->_XF($format); // XF index
+
+ // set _row_sizes so _sizeRow() can use it
+ $this->_row_sizes[$row] = $height;
+
+ // Use setRow($row, null, $XF) to set XF format without setting height
+ if ($height != null) {
+ $miyRw = $height * 20; // row height
+ } else {
+ $miyRw = 0xff; // default row height is 256
+ }
+
+ $level = max(0, min($level, 7)); // level should be between 0 and 7
+ $this->_outline_row_level = max($level, $this->_outline_row_level);
+
+
+ // Set the options flags. fUnsynced is used to show that the font and row
+ // heights are not compatible. This is usually the case for WriteExcel.
+ // The collapsed flag 0x10 doesn't seem to be used to indicate that a row
+ // is collapsed. Instead it is used to indicate that the previous row is
+ // collapsed. The zero height flag, 0x20, is used to collapse a row.
+
+ $grbit |= $level;
+ if ($hidden) {
+ $grbit |= 0x0020;
+ }
+ $grbit |= 0x0040; // fUnsynced
+ if ($format) {
+ $grbit |= 0x0080;
+ }
+ $grbit |= 0x0100;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvvvvvv", $row, $colMic, $colMac, $miyRw,
+ $irwMac,$reserved, $grbit, $ixfe);
+ $this->_append($header.$data);
+ }
+
+ /**
+ * Writes Excel DIMENSIONS to define the area in which there is data.
+ *
+ * @access private
+ */
+ function _storeDimensions()
+ {
+ $record = 0x0200; // Record identifier
+ $row_min = $this->_dim_rowmin; // First row
+ $row_max = $this->_dim_rowmax + 1; // Last row plus 1
+ $col_min = $this->_dim_colmin; // First column
+ $col_max = $this->_dim_colmax + 1; // Last column plus 1
+ $reserved = 0x0000; // Reserved by Excel
+
+ if ($this->_BIFF_version == 0x0500) {
+ $length = 0x000A; // Number of bytes to follow
+ $data = pack("vvvvv", $row_min, $row_max,
+ $col_min, $col_max, $reserved);
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $length = 0x000E;
+ $data = pack("VVvvv", $row_min, $row_max,
+ $col_min, $col_max, $reserved);
+ }
+ $header = pack("vv", $record, $length);
+ $this->_prepend($header.$data);
+ }
+
+ /**
+ * Write BIFF record Window2.
+ *
+ * @access private
+ */
+ function _storeWindow2()
+ {
+ $record = 0x023E; // Record identifier
+ if ($this->_BIFF_version == 0x0500) {
+ $length = 0x000A; // Number of bytes to follow
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $length = 0x0012;
+ }
+
+ $grbit = 0x00B6; // Option flags
+ $rwTop = 0x0000; // Top row visible in window
+ $colLeft = 0x0000; // Leftmost column visible in window
+
+
+ // The options flags that comprise $grbit
+ $fDspFmla = 0; // 0 - bit
+ $fDspGrid = $this->_screen_gridlines; // 1
+ $fDspRwCol = 1; // 2
+ $fFrozen = $this->_frozen; // 3
+ $fDspZeros = 1; // 4
+ $fDefaultHdr = 1; // 5
+ $fArabic = $this->_Arabic; // 6
+ $fDspGuts = $this->_outline_on; // 7
+ $fFrozenNoSplit = 0; // 0 - bit
+ $fSelected = $this->selected; // 1
+ $fPaged = 1; // 2
+
+ $grbit = $fDspFmla;
+ $grbit |= $fDspGrid << 1;
+ $grbit |= $fDspRwCol << 2;
+ $grbit |= $fFrozen << 3;
+ $grbit |= $fDspZeros << 4;
+ $grbit |= $fDefaultHdr << 5;
+ $grbit |= $fArabic << 6;
+ $grbit |= $fDspGuts << 7;
+ $grbit |= $fFrozenNoSplit << 8;
+ $grbit |= $fSelected << 9;
+ $grbit |= $fPaged << 10;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvv", $grbit, $rwTop, $colLeft);
+ // FIXME !!!
+ if ($this->_BIFF_version == 0x0500) {
+ $rgbHdr = 0x00000000; // Row/column heading and gridline color
+ $data .= pack("V", $rgbHdr);
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $rgbHdr = 0x0040; // Row/column heading and gridline color index
+ $zoom_factor_page_break = 0x0000;
+ $zoom_factor_normal = 0x0000;
+ $data .= pack("vvvvV", $rgbHdr, 0x0000, $zoom_factor_page_break, $zoom_factor_normal, 0x00000000);
+ }
+ $this->_append($header.$data);
+ }
+
+ /**
+ * Write BIFF record DEFCOLWIDTH if COLINFO records are in use.
+ *
+ * @access private
+ */
+ function _storeDefcol()
+ {
+ $record = 0x0055; // Record identifier
+ $length = 0x0002; // Number of bytes to follow
+ $colwidth = 0x0008; // Default column width
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $colwidth);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Write BIFF record COLINFO to define column widths
+ *
+ * Note: The SDK says the record length is 0x0B but Excel writes a 0x0C
+ * length record.
+ *
+ * @access private
+ * @param array $col_array This is the only parameter received and is composed of the following:
+ * 0 => First formatted column,
+ * 1 => Last formatted column,
+ * 2 => Col width (8.43 is Excel default),
+ * 3 => The optional XF format of the column,
+ * 4 => Option flags.
+ * 5 => Optional outline level
+ */
+ function _storeColinfo($col_array)
+ {
+ if (isset($col_array[0])) {
+ $colFirst = $col_array[0];
+ }
+ if (isset($col_array[1])) {
+ $colLast = $col_array[1];
+ }
+ if (isset($col_array[2])) {
+ $coldx = $col_array[2];
+ } else {
+ $coldx = 8.43;
+ }
+ if (isset($col_array[3])) {
+ $format = $col_array[3];
+ } else {
+ $format = 0;
+ }
+ if (isset($col_array[4])) {
+ $grbit = $col_array[4];
+ } else {
+ $grbit = 0;
+ }
+ if (isset($col_array[5])) {
+ $level = $col_array[5];
+ } else {
+ $level = 0;
+ }
+ $record = 0x007D; // Record identifier
+ $length = 0x000B; // Number of bytes to follow
+
+ $coldx += 0.72; // Fudge. Excel subtracts 0.72 !?
+ $coldx *= 256; // Convert to units of 1/256 of a char
+
+ $ixfe = $this->_XF($format);
+ $reserved = 0x00; // Reserved
+
+ $level = max(0, min($level, 7));
+ $grbit |= $level << 8;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvvvC", $colFirst, $colLast, $coldx,
+ $ixfe, $grbit, $reserved);
+ $this->_prepend($header.$data);
+ }
+
+ /**
+ * Write BIFF record SELECTION.
+ *
+ * @access private
+ * @param array $array array containing ($rwFirst,$colFirst,$rwLast,$colLast)
+ * @see setSelection()
+ */
+ function _storeSelection($array)
+ {
+ list($rwFirst,$colFirst,$rwLast,$colLast) = $array;
+ $record = 0x001D; // Record identifier
+ $length = 0x000F; // Number of bytes to follow
+
+ $pnn = $this->_active_pane; // Pane position
+ $rwAct = $rwFirst; // Active row
+ $colAct = $colFirst; // Active column
+ $irefAct = 0; // Active cell ref
+ $cref = 1; // Number of refs
+
+ if (!isset($rwLast)) {
+ $rwLast = $rwFirst; // Last row in reference
+ }
+ if (!isset($colLast)) {
+ $colLast = $colFirst; // Last col in reference
+ }
+
+ // Swap last row/col for first row/col as necessary
+ if ($rwFirst > $rwLast) {
+ list($rwFirst, $rwLast) = array($rwLast, $rwFirst);
+ }
+
+ if ($colFirst > $colLast) {
+ list($colFirst, $colLast) = array($colLast, $colFirst);
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("CvvvvvvCC", $pnn, $rwAct, $colAct,
+ $irefAct, $cref,
+ $rwFirst, $rwLast,
+ $colFirst, $colLast);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Store the MERGEDCELLS record for all ranges of merged cells
+ *
+ * @access private
+ */
+ function _storeMergedCells()
+ {
+ // if there are no merged cell ranges set, return
+ if (count($this->_merged_ranges) == 0) {
+ return;
+ }
+ $record = 0x00E5;
+ foreach($this->_merged_ranges as $ranges)
+ {
+ $length = 2 + count($ranges) * 8;
+ $header = pack('vv', $record, $length);
+ $data = pack('v', count($ranges));
+ foreach($ranges as $range)
+ $data .= pack('vvvv', $range[0], $range[2], $range[1], $range[3]);
+ $string=$header.$data;
+ $this->_append(&$string, true);
+ }
+ }
+
+ /**
+ * Write BIFF record EXTERNCOUNT to indicate the number of external sheet
+ * references in a worksheet.
+ *
+ * Excel only stores references to external sheets that are used in formulas.
+ * For simplicity we store references to all the sheets in the workbook
+ * regardless of whether they are used or not. This reduces the overall
+ * complexity and eliminates the need for a two way dialogue between the formula
+ * parser the worksheet objects.
+ *
+ * @access private
+ * @param integer $count The number of external sheet references in this worksheet
+ */
+ function _storeExterncount($count)
+ {
+ $record = 0x0016; // Record identifier
+ $length = 0x0002; // Number of bytes to follow
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $count);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Writes the Excel BIFF EXTERNSHEET record. These references are used by
+ * formulas. A formula references a sheet name via an index. Since we store a
+ * reference to all of the external worksheets the EXTERNSHEET index is the same
+ * as the worksheet index.
+ *
+ * @access private
+ * @param string $sheetname The name of a external worksheet
+ */
+ function _storeExternsheet($sheetname)
+ {
+ $record = 0x0017; // Record identifier
+
+ // References to the current sheet are encoded differently to references to
+ // external sheets.
+ //
+ if ($this->name == $sheetname) {
+ $sheetname = '';
+ $length = 0x02; // The following 2 bytes
+ $cch = 1; // The following byte
+ $rgch = 0x02; // Self reference
+ } else {
+ $length = 0x02 + strlen($sheetname);
+ $cch = strlen($sheetname);
+ $rgch = 0x03; // Reference to a sheet in the current workbook
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("CC", $cch, $rgch);
+ $this->_prepend($header . $data . $sheetname);
+ }
+
+ /**
+ * Writes the Excel BIFF PANE record.
+ * The panes can either be frozen or thawed (unfrozen).
+ * Frozen panes are specified in terms of an integer number of rows and columns.
+ * Thawed panes are specified in terms of Excel's units for rows and columns.
+ *
+ * @access private
+ * @param array $panes This is the only parameter received and is composed of the following:
+ * 0 => Vertical split position,
+ * 1 => Horizontal split position
+ * 2 => Top row visible
+ * 3 => Leftmost column visible
+ * 4 => Active pane
+ */
+ function _storePanes($panes)
+ {
+ $y = $panes[0];
+ $x = $panes[1];
+ $rwTop = $panes[2];
+ $colLeft = $panes[3];
+ if (count($panes) > 4) { // if Active pane was received
+ $pnnAct = $panes[4];
+ } else {
+ $pnnAct = null;
+ }
+ $record = 0x0041; // Record identifier
+ $length = 0x000A; // Number of bytes to follow
+
+ // Code specific to frozen or thawed panes.
+ if ($this->_frozen) {
+ // Set default values for $rwTop and $colLeft
+ if (!isset($rwTop)) {
+ $rwTop = $y;
+ }
+ if (!isset($colLeft)) {
+ $colLeft = $x;
+ }
+ } else {
+ // Set default values for $rwTop and $colLeft
+ if (!isset($rwTop)) {
+ $rwTop = 0;
+ }
+ if (!isset($colLeft)) {
+ $colLeft = 0;
+ }
+
+ // Convert Excel's row and column units to the internal units.
+ // The default row height is 12.75
+ // The default column width is 8.43
+ // The following slope and intersection values were interpolated.
+ //
+ $y = 20*$y + 255;
+ $x = 113.879*$x + 390;
+ }
+
+
+ // Determine which pane should be active. There is also the undocumented
+ // option to override this should it be necessary: may be removed later.
+ //
+ if (!isset($pnnAct)) {
+ if ($x != 0 && $y != 0) {
+ $pnnAct = 0; // Bottom right
+ }
+ if ($x != 0 && $y == 0) {
+ $pnnAct = 1; // Top right
+ }
+ if ($x == 0 && $y != 0) {
+ $pnnAct = 2; // Bottom left
+ }
+ if ($x == 0 && $y == 0) {
+ $pnnAct = 3; // Top left
+ }
+ }
+
+ $this->_active_pane = $pnnAct; // Used in _storeSelection
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvvv", $x, $y, $rwTop, $colLeft, $pnnAct);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Store the page setup SETUP BIFF record.
+ *
+ * @access private
+ */
+ function _storeSetup()
+ {
+ $record = 0x00A1; // Record identifier
+ $length = 0x0022; // Number of bytes to follow
+
+ $iPaperSize = $this->_paper_size; // Paper size
+ $iScale = $this->_print_scale; // Print scaling factor
+ $iPageStart = 0x01; // Starting page number
+ $iFitWidth = $this->_fit_width; // Fit to number of pages wide
+ $iFitHeight = $this->_fit_height; // Fit to number of pages high
+ $grbit = 0x00; // Option flags
+ $iRes = 0x0258; // Print resolution
+ $iVRes = 0x0258; // Vertical print resolution
+ $numHdr = $this->_margin_head; // Header Margin
+ $numFtr = $this->_margin_foot; // Footer Margin
+ $iCopies = 0x01; // Number of copies
+
+ $fLeftToRight = 0x0; // Print over then down
+ $fLandscape = $this->_orientation; // Page orientation
+ $fNoPls = 0x0; // Setup not read from printer
+ $fNoColor = 0x0; // Print black and white
+ $fDraft = 0x0; // Print draft quality
+ $fNotes = 0x0; // Print notes
+ $fNoOrient = 0x0; // Orientation not set
+ $fUsePage = 0x0; // Use custom starting page
+
+ $grbit = $fLeftToRight;
+ $grbit |= $fLandscape << 1;
+ $grbit |= $fNoPls << 2;
+ $grbit |= $fNoColor << 3;
+ $grbit |= $fDraft << 4;
+ $grbit |= $fNotes << 5;
+ $grbit |= $fNoOrient << 6;
+ $grbit |= $fUsePage << 7;
+
+ $numHdr = pack("d", $numHdr);
+ $numFtr = pack("d", $numFtr);
+ if ($this->_byte_order) { // if it's Big Endian
+ $numHdr = strrev($numHdr);
+ $numFtr = strrev($numFtr);
+ }
+
+ $header = pack("vv", $record, $length);
+ $data1 = pack("vvvvvvvv", $iPaperSize,
+ $iScale,
+ $iPageStart,
+ $iFitWidth,
+ $iFitHeight,
+ $grbit,
+ $iRes,
+ $iVRes);
+ $data2 = $numHdr.$numFtr;
+ $data3 = pack("v", $iCopies);
+ $this->_prepend($header . $data1 . $data2 . $data3);
+ }
+
+ /**
+ * Store the header caption BIFF record.
+ *
+ * @access private
+ */
+ function _storeHeader()
+ {
+ $record = 0x0014; // Record identifier
+
+ $str = $this->_header; // header string
+ $cch = strlen($str); // Length of header string
+ if ($this->_BIFF_version == 0x0600) {
+ $encoding = 0x0; // TODO: Unicode support
+ $length = 3 + $cch; // Bytes to follow
+ } else {
+ $length = 1 + $cch; // Bytes to follow
+ }
+
+ $header = pack("vv", $record, $length);
+ if ($this->_BIFF_version == 0x0600) {
+ $data = pack("vC", $cch, $encoding);
+ } else {
+ $data = pack("C", $cch);
+ }
+
+ $this->_prepend($header.$data.$str);
+ }
+
+ /**
+ * Store the footer caption BIFF record.
+ *
+ * @access private
+ */
+ function _storeFooter()
+ {
+ $record = 0x0015; // Record identifier
+
+ $str = $this->_footer; // Footer string
+ $cch = strlen($str); // Length of footer string
+ if ($this->_BIFF_version == 0x0600) {
+ $encoding = 0x0; // TODO: Unicode support
+ $length = 3 + $cch; // Bytes to follow
+ } else {
+ $length = 1 + $cch;
+ }
+
+ $header = pack("vv", $record, $length);
+ if ($this->_BIFF_version == 0x0600) {
+ $data = pack("vC", $cch, $encoding);
+ } else {
+ $data = pack("C", $cch);
+ }
+
+ $this->_prepend($header . $data . $str);
+ }
+
+ /**
+ * Store the horizontal centering HCENTER BIFF record.
+ *
+ * @access private
+ */
+ function _storeHcenter()
+ {
+ $record = 0x0083; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $fHCenter = $this->_hcenter; // Horizontal centering
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $fHCenter);
+
+ $this->_prepend($header.$data);
+ }
+
+ /**
+ * Store the vertical centering VCENTER BIFF record.
+ *
+ * @access private
+ */
+ function _storeVcenter()
+ {
+ $record = 0x0084; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $fVCenter = $this->_vcenter; // Horizontal centering
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $fVCenter);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Store the LEFTMARGIN BIFF record.
+ *
+ * @access private
+ */
+ function _storeMarginLeft()
+ {
+ $record = 0x0026; // Record identifier
+ $length = 0x0008; // Bytes to follow
+
+ $margin = $this->_margin_left; // Margin in inches
+
+ $header = pack("vv", $record, $length);
+ $data = pack("d", $margin);
+ if ($this->_byte_order) { // if it's Big Endian
+ $data = strrev($data);
+ }
+
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Store the RIGHTMARGIN BIFF record.
+ *
+ * @access private
+ */
+ function _storeMarginRight()
+ {
+ $record = 0x0027; // Record identifier
+ $length = 0x0008; // Bytes to follow
+
+ $margin = $this->_margin_right; // Margin in inches
+
+ $header = pack("vv", $record, $length);
+ $data = pack("d", $margin);
+ if ($this->_byte_order) { // if it's Big Endian
+ $data = strrev($data);
+ }
+
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Store the TOPMARGIN BIFF record.
+ *
+ * @access private
+ */
+ function _storeMarginTop()
+ {
+ $record = 0x0028; // Record identifier
+ $length = 0x0008; // Bytes to follow
+
+ $margin = $this->_margin_top; // Margin in inches
+
+ $header = pack("vv", $record, $length);
+ $data = pack("d", $margin);
+ if ($this->_byte_order) { // if it's Big Endian
+ $data = strrev($data);
+ }
+
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Store the BOTTOMMARGIN BIFF record.
+ *
+ * @access private
+ */
+ function _storeMarginBottom()
+ {
+ $record = 0x0029; // Record identifier
+ $length = 0x0008; // Bytes to follow
+
+ $margin = $this->_margin_bottom; // Margin in inches
+
+ $header = pack("vv", $record, $length);
+ $data = pack("d", $margin);
+ if ($this->_byte_order) { // if it's Big Endian
+ $data = strrev($data);
+ }
+
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Merges the area given by its arguments.
+ * This is an Excel97/2000 method. It is required to perform more complicated
+ * merging than the normal setAlign('merge').
+ *
+ * @access public
+ * @param integer $first_row First row of the area to merge
+ * @param integer $first_col First column of the area to merge
+ * @param integer $last_row Last row of the area to merge
+ * @param integer $last_col Last column of the area to merge
+ */
+ function mergeCells($first_row, $first_col, $last_row, $last_col)
+ {
+ $record = 0x00E5; // Record identifier
+ $length = 0x000A; // Bytes to follow
+ $cref = 1; // Number of refs
+
+ // Swap last row/col for first row/col as necessary
+ if ($first_row > $last_row) {
+ list($first_row, $last_row) = array($last_row, $first_row);
+ }
+
+ if ($first_col > $last_col) {
+ list($first_col, $last_col) = array($last_col, $first_col);
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvvv", $cref, $first_row, $last_row,
+ $first_col, $last_col);
+
+ $this->_append($header.$data);
+ }
+
+ /**
+ * Write the PRINTHEADERS BIFF record.
+ *
+ * @access private
+ */
+ function _storePrintHeaders()
+ {
+ $record = 0x002a; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $fPrintRwCol = $this->_print_headers; // Boolean flag
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $fPrintRwCol);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the
+ * GRIDSET record.
+ *
+ * @access private
+ */
+ function _storePrintGridlines()
+ {
+ $record = 0x002b; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $fPrintGrid = $this->_print_gridlines; // Boolean flag
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $fPrintGrid);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Write the GRIDSET BIFF record. Must be used in conjunction with the
+ * PRINTGRIDLINES record.
+ *
+ * @access private
+ */
+ function _storeGridset()
+ {
+ $record = 0x0082; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $fGridSet = !($this->_print_gridlines); // Boolean flag
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $fGridSet);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Write the GUTS BIFF record. This is used to configure the gutter margins
+ * where Excel outline symbols are displayed. The visibility of the gutters is
+ * controlled by a flag in WSBOOL.
+ *
+ * @see _storeWsbool()
+ * @access private
+ */
+ function _storeGuts()
+ {
+ $record = 0x0080; // Record identifier
+ $length = 0x0008; // Bytes to follow
+
+ $dxRwGut = 0x0000; // Size of row gutter
+ $dxColGut = 0x0000; // Size of col gutter
+
+ $row_level = $this->_outline_row_level;
+ $col_level = 0;
+
+ // Calculate the maximum column outline level. The equivalent calculation
+ // for the row outline level is carried out in setRow().
+ $colcount = count($this->_colinfo);
+ for ($i = 0; $i < $colcount; $i++) {
+ // Skip cols without outline level info.
+ if (count($this->_colinfo[$i]) >= 6) {
+ $col_level = max($this->_colinfo[$i][5], $col_level);
+ }
+ }
+
+ // Set the limits for the outline levels (0 <= x <= 7).
+ $col_level = max(0, min($col_level, 7));
+
+ // The displayed level is one greater than the max outline levels
+ if ($row_level) {
+ $row_level++;
+ }
+ if ($col_level) {
+ $col_level++;
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvv", $dxRwGut, $dxColGut, $row_level, $col_level);
+
+ $this->_prepend($header.$data);
+ }
+
+
+ /**
+ * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction
+ * with the SETUP record.
+ *
+ * @access private
+ */
+ function _storeWsbool()
+ {
+ $record = 0x0081; // Record identifier
+ $length = 0x0002; // Bytes to follow
+ $grbit = 0x0000;
+
+ // The only option that is of interest is the flag for fit to page. So we
+ // set all the options in one go.
+ //
+ /*if ($this->_fit_page) {
+ $grbit = 0x05c1;
+ } else {
+ $grbit = 0x04c1;
+ }*/
+ // Set the option flags
+ $grbit |= 0x0001; // Auto page breaks visible
+ if ($this->_outline_style) {
+ $grbit |= 0x0020; // Auto outline styles
+ }
+ if ($this->_outline_below) {
+ $grbit |= 0x0040; // Outline summary below
+ }
+ if ($this->_outline_right) {
+ $grbit |= 0x0080; // Outline summary right
+ }
+ if ($this->_fit_page) {
+ $grbit |= 0x0100; // Page setup fit to page
+ }
+ if ($this->_outline_on) {
+ $grbit |= 0x0400; // Outline symbols displayed
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $grbit);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Write the HORIZONTALPAGEBREAKS BIFF record.
+ *
+ * @access private
+ */
+ function _storeHbreak()
+ {
+ // Return if the user hasn't specified pagebreaks
+ if (empty($this->_hbreaks)) {
+ return;
+ }
+
+ // Sort and filter array of page breaks
+ $breaks = $this->_hbreaks;
+ sort($breaks, SORT_NUMERIC);
+ if ($breaks[0] == 0) { // don't use first break if it's 0
+ array_shift($breaks);
+ }
+
+ $record = 0x001b; // Record identifier
+ $cbrk = count($breaks); // Number of page breaks
+ if ($this->_BIFF_version == 0x0600) {
+ $length = 2 + 6*$cbrk; // Bytes to follow
+ } else {
+ $length = 2 + 2*$cbrk; // Bytes to follow
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $cbrk);
+
+ // Append each page break
+ foreach ($breaks as $break) {
+ if ($this->_BIFF_version == 0x0600) {
+ $data .= pack("vvv", $break, 0x0000, 0x00ff);
+ } else {
+ $data .= pack("v", $break);
+ }
+ }
+
+ $this->_prepend($header.$data);
+ }
+
+
+ /**
+ * Write the VERTICALPAGEBREAKS BIFF record.
+ *
+ * @access private
+ */
+ function _storeVbreak()
+ {
+ // Return if the user hasn't specified pagebreaks
+ if (empty($this->_vbreaks)) {
+ return;
+ }
+
+ // 1000 vertical pagebreaks appears to be an internal Excel 5 limit.
+ // It is slightly higher in Excel 97/200, approx. 1026
+ $breaks = array_slice($this->_vbreaks,0,1000);
+
+ // Sort and filter array of page breaks
+ sort($breaks, SORT_NUMERIC);
+ if ($breaks[0] == 0) { // don't use first break if it's 0
+ array_shift($breaks);
+ }
+
+ $record = 0x001a; // Record identifier
+ $cbrk = count($breaks); // Number of page breaks
+ if ($this->_BIFF_version == 0x0600) {
+ $length = 2 + 6*$cbrk; // Bytes to follow
+ } else {
+ $length = 2 + 2*$cbrk; // Bytes to follow
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $cbrk);
+
+ // Append each page break
+ foreach ($breaks as $break) {
+ if ($this->_BIFF_version == 0x0600) {
+ $data .= pack("vvv", $break, 0x0000, 0xffff);
+ } else {
+ $data .= pack("v", $break);
+ }
+ }
+
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Set the Biff PROTECT record to indicate that the worksheet is protected.
+ *
+ * @access private
+ */
+ function _storeProtect()
+ {
+ // Exit unless sheet protection has been specified
+ if ($this->_protect == 0) {
+ return;
+ }
+
+ $record = 0x0012; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $fLock = $this->_protect; // Worksheet is protected
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $fLock);
+
+ $this->_prepend($header.$data);
+ }
+
+ /**
+ * Write the worksheet PASSWORD record.
+ *
+ * @access private
+ */
+ function _storePassword()
+ {
+ // Exit unless sheet protection and password have been specified
+ if (($this->_protect == 0) || (!isset($this->_password))) {
+ return;
+ }
+
+ $record = 0x0013; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $wPassword = $this->_password; // Encoded password
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $wPassword);
+
+ $this->_prepend($header . $data);
+ }
+
+
+ /**
+ * Insert a 24bit bitmap image in a worksheet.
+ *
+ * @access public
+ * @param integer $row The row we are going to insert the bitmap into
+ * @param integer $col The column we are going to insert the bitmap into
+ * @param string $bitmap The bitmap filename
+ * @param integer $x The horizontal position (offset) of the image inside the cell.
+ * @param integer $y The vertical position (offset) of the image inside the cell.
+ * @param integer $scale_x The horizontal scale
+ * @param integer $scale_y The vertical scale
+ */
+ function insertBitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1)
+ {
+ $bitmap_array = $this->_processBitmap($bitmap);
+ if ($this->isError($bitmap_array)) {
+ $this->writeString($row, $col, $bitmap_array->getMessage());
+ return;
+ }
+ list($width, $height, $size, $data) = $bitmap_array; //$this->_processBitmap($bitmap);
+
+ // Scale the frame of the image.
+ $width *= $scale_x;
+ $height *= $scale_y;
+
+ // Calculate the vertices of the image and write the OBJ record
+ $this->_positionImage($col, $row, $x, $y, $width, $height);
+
+ // Write the IMDATA record to store the bitmap data
+ $record = 0x007f;
+ $length = 8 + $size;
+ $cf = 0x09;
+ $env = 0x01;
+ $lcb = $size;
+
+ $header = pack("vvvvV", $record, $length, $cf, $env, $lcb);
+ $this->_append($header.$data);
+ }
+
+ /**
+ * Calculate the vertices that define the position of the image as required by
+ * the OBJ record.
+ *
+ * +------------+------------+
+ * | A | B |
+ * +-----+------------+------------+
+ * | |(x1,y1) | |
+ * | 1 |(A1)._______|______ |
+ * | | | | |
+ * | | | | |
+ * +-----+----| BITMAP |-----+
+ * | | | | |
+ * | 2 | |______________. |
+ * | | | (B2)|
+ * | | | (x2,y2)|
+ * +---- +------------+------------+
+ *
+ * Example of a bitmap that covers some of the area from cell A1 to cell B2.
+ *
+ * Based on the width and height of the bitmap we need to calculate 8 vars:
+ * $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2.
+ * The width and height of the cells are also variable and have to be taken into
+ * account.
+ * The values of $col_start and $row_start are passed in from the calling
+ * function. The values of $col_end and $row_end are calculated by subtracting
+ * the width and height of the bitmap from the width and height of the
+ * underlying cells.
+ * The vertices are expressed as a percentage of the underlying cell width as
+ * follows (rhs values are in pixels):
+ *
+ * x1 = X / W *1024
+ * y1 = Y / H *256
+ * x2 = (X-1) / W *1024
+ * y2 = (Y-1) / H *256
+ *
+ * Where: X is distance from the left side of the underlying cell
+ * Y is distance from the top of the underlying cell
+ * W is the width of the cell
+ * H is the height of the cell
+ *
+ * @access private
+ * @note the SDK incorrectly states that the height should be expressed as a
+ * percentage of 1024.
+ * @param integer $col_start Col containing upper left corner of object
+ * @param integer $row_start Row containing top left corner of object
+ * @param integer $x1 Distance to left side of object
+ * @param integer $y1 Distance to top of object
+ * @param integer $width Width of image frame
+ * @param integer $height Height of image frame
+ */
+ function _positionImage($col_start, $row_start, $x1, $y1, $width, $height)
+ {
+ // Initialise end cell to the same as the start cell
+ $col_end = $col_start; // Col containing lower right corner of object
+ $row_end = $row_start; // Row containing bottom right corner of object
+
+ // Zero the specified offset if greater than the cell dimensions
+ if ($x1 >= $this->_sizeCol($col_start)) {
+ $x1 = 0;
+ }
+ if ($y1 >= $this->_sizeRow($row_start)) {
+ $y1 = 0;
+ }
+
+ $width = $width + $x1 -1;
+ $height = $height + $y1 -1;
+
+ // Subtract the underlying cell widths to find the end cell of the image
+ while ($width >= $this->_sizeCol($col_end)) {
+ $width -= $this->_sizeCol($col_end);
+ $col_end++;
+ }
+
+ // Subtract the underlying cell heights to find the end cell of the image
+ while ($height >= $this->_sizeRow($row_end)) {
+ $height -= $this->_sizeRow($row_end);
+ $row_end++;
+ }
+
+ // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
+ // with zero eight or width.
+ //
+ if ($this->_sizeCol($col_start) == 0) {
+ return;
+ }
+ if ($this->_sizeCol($col_end) == 0) {
+ return;
+ }
+ if ($this->_sizeRow($row_start) == 0) {
+ return;
+ }
+ if ($this->_sizeRow($row_end) == 0) {
+ return;
+ }
+
+ // Convert the pixel values to the percentage value expected by Excel
+ $x1 = $x1 / $this->_sizeCol($col_start) * 1024;
+ $y1 = $y1 / $this->_sizeRow($row_start) * 256;
+ $x2 = $width / $this->_sizeCol($col_end) * 1024; // Distance to right side of object
+ $y2 = $height / $this->_sizeRow($row_end) * 256; // Distance to bottom of object
+
+ $this->_storeObjPicture($col_start, $x1,
+ $row_start, $y1,
+ $col_end, $x2,
+ $row_end, $y2);
+ }
+
+ /**
+ * Convert the width of a cell from user's units to pixels. By interpolation
+ * the relationship is: y = 7x +5. If the width hasn't been set by the user we
+ * use the default value. If the col is hidden we use a value of zero.
+ *
+ * @access private
+ * @param integer $col The column
+ * @return integer The width in pixels
+ */
+ function _sizeCol($col)
+ {
+ // Look up the cell value to see if it has been changed
+ if (isset($this->col_sizes[$col])) {
+ if ($this->col_sizes[$col] == 0) {
+ return(0);
+ } else {
+ return(floor(7 * $this->col_sizes[$col] + 5));
+ }
+ } else {
+ return(64);
+ }
+ }
+
+ /**
+ * Convert the height of a cell from user's units to pixels. By interpolation
+ * the relationship is: y = 4/3x. If the height hasn't been set by the user we
+ * use the default value. If the row is hidden we use a value of zero. (Not
+ * possible to hide row yet).
+ *
+ * @access private
+ * @param integer $row The row
+ * @return integer The width in pixels
+ */
+ function _sizeRow($row)
+ {
+ // Look up the cell value to see if it has been changed
+ if (isset($this->_row_sizes[$row])) {
+ if ($this->_row_sizes[$row] == 0) {
+ return(0);
+ } else {
+ return(floor(4/3 * $this->_row_sizes[$row]));
+ }
+ } else {
+ return(17);
+ }
+ }
+
+ /**
+ * Store the OBJ record that precedes an IMDATA record. This could be generalise
+ * to support other Excel objects.
+ *
+ * @access private
+ * @param integer $colL Column containing upper left corner of object
+ * @param integer $dxL Distance from left side of cell
+ * @param integer $rwT Row containing top left corner of object
+ * @param integer $dyT Distance from top of cell
+ * @param integer $colR Column containing lower right corner of object
+ * @param integer $dxR Distance from right of cell
+ * @param integer $rwB Row containing bottom right corner of object
+ * @param integer $dyB Distance from bottom of cell
+ */
+ function _storeObjPicture($colL,$dxL,$rwT,$dyT,$colR,$dxR,$rwB,$dyB)
+ {
+ $record = 0x005d; // Record identifier
+ $length = 0x003c; // Bytes to follow
+
+ $cObj = 0x0001; // Count of objects in file (set to 1)
+ $OT = 0x0008; // Object type. 8 = Picture
+ $id = 0x0001; // Object ID
+ $grbit = 0x0614; // Option flags
+
+ $cbMacro = 0x0000; // Length of FMLA structure
+ $Reserved1 = 0x0000; // Reserved
+ $Reserved2 = 0x0000; // Reserved
+
+ $icvBack = 0x09; // Background colour
+ $icvFore = 0x09; // Foreground colour
+ $fls = 0x00; // Fill pattern
+ $fAuto = 0x00; // Automatic fill
+ $icv = 0x08; // Line colour
+ $lns = 0xff; // Line style
+ $lnw = 0x01; // Line weight
+ $fAutoB = 0x00; // Automatic border
+ $frs = 0x0000; // Frame style
+ $cf = 0x0009; // Image format, 9 = bitmap
+ $Reserved3 = 0x0000; // Reserved
+ $cbPictFmla = 0x0000; // Length of FMLA structure
+ $Reserved4 = 0x0000; // Reserved
+ $grbit2 = 0x0001; // Option flags
+ $Reserved5 = 0x0000; // Reserved
+
+
+ $header = pack("vv", $record, $length);
+ $data = pack("V", $cObj);
+ $data .= pack("v", $OT);
+ $data .= pack("v", $id);
+ $data .= pack("v", $grbit);
+ $data .= pack("v", $colL);
+ $data .= pack("v", $dxL);
+ $data .= pack("v", $rwT);
+ $data .= pack("v", $dyT);
+ $data .= pack("v", $colR);
+ $data .= pack("v", $dxR);
+ $data .= pack("v", $rwB);
+ $data .= pack("v", $dyB);
+ $data .= pack("v", $cbMacro);
+ $data .= pack("V", $Reserved1);
+ $data .= pack("v", $Reserved2);
+ $data .= pack("C", $icvBack);
+ $data .= pack("C", $icvFore);
+ $data .= pack("C", $fls);
+ $data .= pack("C", $fAuto);
+ $data .= pack("C", $icv);
+ $data .= pack("C", $lns);
+ $data .= pack("C", $lnw);
+ $data .= pack("C", $fAutoB);
+ $data .= pack("v", $frs);
+ $data .= pack("V", $cf);
+ $data .= pack("v", $Reserved3);
+ $data .= pack("v", $cbPictFmla);
+ $data .= pack("v", $Reserved4);
+ $data .= pack("v", $grbit2);
+ $data .= pack("V", $Reserved5);
+
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Convert a 24 bit bitmap into the modified internal format used by Windows.
+ * This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
+ * MSDN library.
+ *
+ * @access private
+ * @param string $bitmap The bitmap to process
+ * @return array Array with data and properties of the bitmap
+ */
+ function _processBitmap($bitmap)
+ {
+ // Open file.
+ $bmp_fd = @fopen($bitmap,"rb");
+ if (!$bmp_fd) {
+ $this->raiseError("Couldn't import $bitmap");
+ }
+
+ // Slurp the file into a string.
+ $data = fread($bmp_fd, filesize($bitmap));
+
+ // Check that the file is big enough to be a bitmap.
+ if (strlen($data) <= 0x36) {
+ $this->raiseError("$bitmap doesn't contain enough data.\n");
+ }
+
+ // The first 2 bytes are used to identify the bitmap.
+ $identity = unpack("A2ident", $data);
+ if ($identity['ident'] != "BM") {
+ $this->raiseError("$bitmap doesn't appear to be a valid bitmap image.\n");
+ }
+
+ // Remove bitmap data: ID.
+ $data = substr($data, 2);
+
+ // Read and remove the bitmap size. This is more reliable than reading
+ // the data size at offset 0x22.
+ //
+ $size_array = unpack("Vsa", substr($data, 0, 4));
+ $size = $size_array['sa'];
+ $data = substr($data, 4);
+ $size -= 0x36; // Subtract size of bitmap header.
+ $size += 0x0C; // Add size of BIFF header.
+
+ // Remove bitmap data: reserved, offset, header length.
+ $data = substr($data, 12);
+
+ // Read and remove the bitmap width and height. Verify the sizes.
+ $width_and_height = unpack("V2", substr($data, 0, 8));
+ $width = $width_and_height[1];
+ $height = $width_and_height[2];
+ $data = substr($data, 8);
+ if ($width > 0xFFFF) {
+ $this->raiseError("$bitmap: largest image width supported is 65k.\n");
+ }
+ if ($height > 0xFFFF) {
+ $this->raiseError("$bitmap: largest image height supported is 65k.\n");
+ }
+
+ // Read and remove the bitmap planes and bpp data. Verify them.
+ $planes_and_bitcount = unpack("v2", substr($data, 0, 4));
+ $data = substr($data, 4);
+ if ($planes_and_bitcount[2] != 24) { // Bitcount
+ $this->raiseError("$bitmap isn't a 24bit true color bitmap.\n");
+ }
+ if ($planes_and_bitcount[1] != 1) {
+ $this->raiseError("$bitmap: only 1 plane supported in bitmap image.\n");
+ }
+
+ // Read and remove the bitmap compression. Verify compression.
+ $compression = unpack("Vcomp", substr($data, 0, 4));
+ $data = substr($data, 4);
+
+ //$compression = 0;
+ if ($compression['comp'] != 0) {
+ $this->raiseError("$bitmap: compression not supported in bitmap image.\n");
+ }
+
+ // Remove bitmap data: data size, hres, vres, colours, imp. colours.
+ $data = substr($data, 20);
+
+ // Add the BITMAPCOREHEADER data
+ $header = pack("Vvvvv", 0x000c, $width, $height, 0x01, 0x18);
+ $data = $header . $data;
+
+ return (array($width, $height, $size, $data));
+ }
+
+ /**
+ * Store the window zoom factor. This should be a reduced fraction but for
+ * simplicity we will store all fractions with a numerator of 100.
+ *
+ * @access private
+ */
+ function _storeZoom()
+ {
+ // If scale is 100 we don't need to write a record
+ if ($this->_zoom == 100) {
+ return;
+ }
+
+ $record = 0x00A0; // Record identifier
+ $length = 0x0004; // Bytes to follow
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vv", $this->_zoom, 100);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * FIXME: add comments
+ */
+ function setValidation($row1, $col1, $row2, $col2, &$validator)
+ {
+ $this->_dv[] = $validator->_getData() .
+ pack("vvvvv", 1, $row1, $row2, $col1, $col2);
+ }
+
+ /**
+ * Store the DVAL and DV records.
+ *
+ * @access private
+ */
+ function _storeDataValidity()
+ {
+ $record = 0x01b2; // Record identifier
+ $length = 0x0012; // Bytes to follow
+
+ $grbit = 0x0002; // Prompt box at cell, no cached validity data at DV records
+ $horPos = 0x00000000; // Horizontal position of prompt box, if fixed position
+ $verPos = 0x00000000; // Vertical position of prompt box, if fixed position
+ $objId = 0xffffffff; // Object identifier of drop down arrow object, or -1 if not visible
+
+ $header = pack('vv', $record, $length);
+ $data = pack('vVVVV', $grbit, $horPos, $verPos, $objId,
+ count($this->_dv));
+ $this->_append($header.$data);
+
+ $record = 0x01be; // Record identifier
+ foreach ($this->_dv as $dv) {
+ $length = strlen($dv); // Bytes to follow
+ $header = pack("vv", $record, $length);
+ $this->_append($header . $dv);
+ }
+ }
+}
+?>
diff --git a/vendor/library/Excel/demo.php b/vendor/library/Excel/demo.php
new file mode 100644
index 0000000..ceee7a5
--- /dev/null
+++ b/vendor/library/Excel/demo.php
@@ -0,0 +1,81 @@
+addFormat();
+$format_und->setBottom(2);//thick
+$format_und->setBold();
+$format_und->setBgColor('black');
+$format_und->setColor('white');
+$format_und->setFontFamily('Arial');
+$format_und->setSize(8);
+
+$format_reg =& $workbook->addFormat();
+$format_reg->setColor('black');
+$format_reg->setFontFamily('Arial');
+$format_reg->setSize(8);
+
+$arr = array(
+ 'Calendar'=>$sheet1,
+ 'Names' =>$sheet2,
+ );
+
+foreach($arr as $wbname=>$rows)
+{
+ $rowcount = count($rows);
+ $colcount = count($rows[0]);
+
+ $worksheet =& $workbook->addWorksheet($wbname);
+
+
+
+ $worksheet->setColumn(0,0, 6.14);//setColumn(startcol,endcol,float)
+ $worksheet->setColumn(1,3,15.00);
+ $worksheet->setColumn(4,4, 8.00);
+
+ for( $j=0; $j<$rowcount; $j++ )
+ {
+ for($i=0; $i<$colcount;$i++)
+ {
+ $fmt =& $format_reg;
+ if ($j==0)
+ $fmt =& $format_und;
+
+ if (isset($rows[$j][$i]))
+ {
+ $data=$rows[$j][$i];
+ $worksheet->write($j, $i, $data, $fmt);
+ }
+ }
+ }
+}
+
+$workbook->send('test.xls');
+$workbook->close();
+
+//-----------------------------------------------------------------------------
+?>
+
diff --git a/vendor/library/Excel/excel.php b/vendor/library/Excel/excel.php
new file mode 100644
index 0000000..4f33e3b
--- /dev/null
+++ b/vendor/library/Excel/excel.php
@@ -0,0 +1,65 @@
+addFormat();
+ $header->setBottom(2);//thick
+ $header->setBold();
+ $header->setBgColor('black');
+ $header->setFgColor(22);
+ $header->setColor('black');
+ $header->setFontFamily('Arial');
+ $header->setSize(8);
+ $header->setAlign('center');
+
+ //Criação da página
+ $worksheet =& $workbook->addWorksheet("Lista");
+
+ //Defino o body da planilha
+ $body =& $workbook->addFormat();
+ $body->setColor('black');
+ $body->setFontFamily('Arial');
+ $body->setSize(8);
+
+ //Definições das colunas
+ $worksheet->setColumn(0,0,30);//Coluna inicial, coluna final, largura
+ $worksheet->setColumn(1,1,30);
+ $worksheet->setColumn(2,2,5);
+ $worksheet->setColumn(3,3,10);
+ $worksheet->setColumn(4,5,12);
+
+ //Escrevendo o header da planilha
+ $worksheet->write(0, 0, "NOME", $header);//Linha, coluna, label, parametros
+ $worksheet->write(0, 1, "E-MAIL", $header);
+ $worksheet->write(0, 2, "SEXO", $header);
+ $worksheet->write(0, 3, "NASCIMENTO", $header);
+ $worksheet->write(0, 4, "CPF", $header);
+
+ $line=1;//Linha inicial
+ $col=0;//Coluna inicial
+
+ for($i=0;$i<10;$i++)
+ {
+
+ //Escrevendo o body da planilha
+ $worksheet->write($line, $col++, "Kenio de Souza", $body);
+ $worksheet->write($line, $col++, "kenio_souza@hotmail.com", $body);
+ $worksheet->write($line, $col++, "M", $body);
+ $worksheet->write($line, $col++, "07/09/1977", $body);
+ $worksheet->writeString($line, $col++, rand(0,99999999999), $body);
+ //Obs: Utiliza-se writeString para escrever numeros em forma de string,
+ //senão o excel irá ignorar os zeros a esquerda
+
+ $line++;
+ $col=0;
+ }
+
+ //Envio o arquivo para download
+ //$workbook->send(date("Y-m-d").'-'.rand(999,99999).'.xls');
+ $workbook->close();
\ No newline at end of file
diff --git a/vendor/library/Excel/oleread.inc b/vendor/library/Excel/oleread.inc
new file mode 100644
index 0000000..0ac868a
--- /dev/null
+++ b/vendor/library/Excel/oleread.inc
@@ -0,0 +1,271 @@
+=4294967294)
+ {
+ $value=-2;
+ }
+ return $value;
+}
+
+
+class OLERead {
+ var $data = '';
+
+
+ function OLERead(){
+
+
+ }
+
+ function read($sFileName){
+
+ // check if file exist and is readable (Darko Miljanovic)
+ if(!is_readable($sFileName)) {
+ $this->error = 1;
+ return false;
+ }
+
+ $this->data = @file_get_contents($sFileName);
+ if (!$this->data) {
+ $this->error = 1;
+ return false;
+ }
+ //echo IDENTIFIER_OLE;
+ //echo 'start';
+ if (substr($this->data, 0, 8) != IDENTIFIER_OLE) {
+ $this->error = 1;
+ return false;
+ }
+ $this->numBigBlockDepotBlocks = GetInt4d($this->data, NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
+ $this->sbdStartBlock = GetInt4d($this->data, SMALL_BLOCK_DEPOT_BLOCK_POS);
+ $this->rootStartBlock = GetInt4d($this->data, ROOT_START_BLOCK_POS);
+ $this->extensionBlock = GetInt4d($this->data, EXTENSION_BLOCK_POS);
+ $this->numExtensionBlocks = GetInt4d($this->data, NUM_EXTENSION_BLOCK_POS);
+
+ /*
+ echo $this->numBigBlockDepotBlocks." ";
+ echo $this->sbdStartBlock." ";
+ echo $this->rootStartBlock." ";
+ echo $this->extensionBlock." ";
+ echo $this->numExtensionBlocks." ";
+ */
+ //echo "sbdStartBlock = $this->sbdStartBlock\n";
+ $bigBlockDepotBlocks = array();
+ $pos = BIG_BLOCK_DEPOT_BLOCKS_POS;
+ // echo "pos = $pos";
+ $bbdBlocks = $this->numBigBlockDepotBlocks;
+
+ if ($this->numExtensionBlocks != 0) {
+ $bbdBlocks = (BIG_BLOCK_SIZE - BIG_BLOCK_DEPOT_BLOCKS_POS)/4;
+ }
+
+ for ($i = 0; $i < $bbdBlocks; $i++) {
+ $bigBlockDepotBlocks[$i] = GetInt4d($this->data, $pos);
+ $pos += 4;
+ }
+
+
+ for ($j = 0; $j < $this->numExtensionBlocks; $j++) {
+ $pos = ($this->extensionBlock + 1) * BIG_BLOCK_SIZE;
+ $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, BIG_BLOCK_SIZE / 4 - 1);
+
+ for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; $i++) {
+ $bigBlockDepotBlocks[$i] = GetInt4d($this->data, $pos);
+ $pos += 4;
+ }
+
+ $bbdBlocks += $blocksToRead;
+ if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
+ $this->extensionBlock = GetInt4d($this->data, $pos);
+ }
+ }
+
+ // var_dump($bigBlockDepotBlocks);
+
+ // readBigBlockDepot
+ $pos = 0;
+ $index = 0;
+ $this->bigBlockChain = array();
+
+ for ($i = 0; $i < $this->numBigBlockDepotBlocks; $i++) {
+ $pos = ($bigBlockDepotBlocks[$i] + 1) * BIG_BLOCK_SIZE;
+ //echo "pos = $pos";
+ for ($j = 0 ; $j < BIG_BLOCK_SIZE / 4; $j++) {
+ $this->bigBlockChain[$index] = GetInt4d($this->data, $pos);
+ $pos += 4 ;
+ $index++;
+ }
+ }
+
+ //var_dump($this->bigBlockChain);
+ //echo '=====2';
+ // readSmallBlockDepot();
+ $pos = 0;
+ $index = 0;
+ $sbdBlock = $this->sbdStartBlock;
+ $this->smallBlockChain = array();
+
+ while ($sbdBlock != -2) {
+
+ $pos = ($sbdBlock + 1) * BIG_BLOCK_SIZE;
+
+ for ($j = 0; $j < BIG_BLOCK_SIZE / 4; $j++) {
+ $this->smallBlockChain[$index] = GetInt4d($this->data, $pos);
+ $pos += 4;
+ $index++;
+ }
+
+ $sbdBlock = $this->bigBlockChain[$sbdBlock];
+ }
+
+
+ // readData(rootStartBlock)
+ $block = $this->rootStartBlock;
+ $pos = 0;
+ $this->entry = $this->__readData($block);
+
+ /*
+ while ($block != -2) {
+ $pos = ($block + 1) * BIG_BLOCK_SIZE;
+ $this->entry = $this->entry.substr($this->data, $pos, BIG_BLOCK_SIZE);
+ $block = $this->bigBlockChain[$block];
+ }
+ */
+ //echo '==='.$this->entry."===";
+ $this->__readPropertySets();
+
+ }
+
+ function __readData($bl) {
+ $block = $bl;
+ $pos = 0;
+ $data = '';
+
+ while ($block != -2) {
+ $pos = ($block + 1) * BIG_BLOCK_SIZE;
+ $data = $data.substr($this->data, $pos, BIG_BLOCK_SIZE);
+ //echo "pos = $pos data=$data\n";
+ $block = $this->bigBlockChain[$block];
+ }
+ return $data;
+ }
+
+ function __readPropertySets(){
+ $offset = 0;
+ //var_dump($this->entry);
+ while ($offset < strlen($this->entry)) {
+ $d = substr($this->entry, $offset, PROPERTY_STORAGE_BLOCK_SIZE);
+
+ $nameSize = ord($d[SIZE_OF_NAME_POS]) | (ord($d[SIZE_OF_NAME_POS+1]) << 8);
+
+ $type = ord($d[TYPE_POS]);
+ //$maxBlock = strlen($d) / BIG_BLOCK_SIZE - 1;
+
+ $startBlock = GetInt4d($d, START_BLOCK_POS);
+ $size = GetInt4d($d, SIZE_POS);
+
+ $name = '';
+ for ($i = 0; $i < $nameSize ; $i++) {
+ $name .= $d[$i];
+ }
+
+ $name = str_replace("\x00", "", $name);
+
+ $this->props[] = array (
+ 'name' => $name,
+ 'type' => $type,
+ 'startBlock' => $startBlock,
+ 'size' => $size);
+
+ if (($name == "Workbook") || ($name == "Book")) {
+ $this->wrkbook = count($this->props) - 1;
+ }
+
+ if ($name == "Root Entry") {
+ $this->rootentry = count($this->props) - 1;
+ }
+
+ //echo "name ==$name=\n";
+
+
+ $offset += PROPERTY_STORAGE_BLOCK_SIZE;
+ }
+
+ }
+
+
+ function getWorkBook(){
+ if ($this->props[$this->wrkbook]['size'] < SMALL_BLOCK_THRESHOLD){
+// getSmallBlockStream(PropertyStorage ps)
+
+ $rootdata = $this->__readData($this->props[$this->rootentry]['startBlock']);
+
+ $streamData = '';
+ $block = $this->props[$this->wrkbook]['startBlock'];
+ //$count = 0;
+ $pos = 0;
+ while ($block != -2) {
+ $pos = $block * SMALL_BLOCK_SIZE;
+ $streamData .= substr($rootdata, $pos, SMALL_BLOCK_SIZE);
+
+ $block = $this->smallBlockChain[$block];
+ }
+
+ return $streamData;
+
+
+ }else{
+
+ $numBlocks = $this->props[$this->wrkbook]['size'] / BIG_BLOCK_SIZE;
+ if ($this->props[$this->wrkbook]['size'] % BIG_BLOCK_SIZE != 0) {
+ $numBlocks++;
+ }
+
+ if ($numBlocks == 0) return '';
+
+ //echo "numBlocks = $numBlocks\n";
+ //byte[] streamData = new byte[numBlocks * BIG_BLOCK_SIZE];
+ //print_r($this->wrkbook);
+ $streamData = '';
+ $block = $this->props[$this->wrkbook]['startBlock'];
+ //$count = 0;
+ $pos = 0;
+ //echo "block = $block";
+ while ($block != -2) {
+ $pos = ($block + 1) * BIG_BLOCK_SIZE;
+ $streamData .= substr($this->data, $pos, BIG_BLOCK_SIZE);
+ $block = $this->bigBlockChain[$block];
+ }
+ //echo 'stream'.$streamData;
+ return $streamData;
+ }
+ }
+
+}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/ChainedBlockStream.php b/vendor/library/Excel/phpxls/ChainedBlockStream.php
new file mode 100644
index 0000000..edde829
--- /dev/null
+++ b/vendor/library/Excel/phpxls/ChainedBlockStream.php
@@ -0,0 +1,229 @@
+
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: ChainedBlockStream.php,v 1.1 2007/02/13 21:00:42 schmidt Exp $
+ * @link http://pear.php.net/package/OLE
+ * @since File available since Release 0.6.0
+ */
+
+require_once 'PEAR.php';
+require_once 'OLE.php';
+
+/**
+ * Stream wrapper for reading data stored in an OLE file. Implements methods
+ * for PHP's stream_wrapper_register(). For creating streams using this
+ * wrapper, use OLE_PPS_File::getStream().
+ *
+ * @category Structures
+ * @package OLE
+ * @author Christian Schmidt
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/OLE
+ * @since Class available since Release 0.6.0
+ */
+class OLE_ChainedBlockStream extends PEAR
+{
+ /**
+ * The OLE container of the file that is being read.
+ * @var OLE
+ */
+ var $ole;
+
+ /**
+ * Parameters specified by fopen().
+ * @var array
+ */
+ var $params;
+
+ /**
+ * The binary data of the file.
+ * @var string
+ */
+ var $data;
+
+ /**
+ * The file pointer.
+ * @var int byte offset
+ */
+ var $pos;
+
+ /**
+ * Implements support for fopen().
+ * For creating streams using this wrapper, use OLE_PPS_File::getStream().
+ * @param string resource name including scheme, e.g.
+ * ole-chainedblockstream://oleInstanceId=1
+ * @param string only "r" is supported
+ * @param int mask of STREAM_REPORT_ERRORS and STREAM_USE_PATH
+ * @param string absolute path of the opened stream (out parameter)
+ * @return bool true on success
+ */
+ function stream_open($path, $mode, $options, &$openedPath)
+ {
+ if ($mode != 'r') {
+ if ($options & STREAM_REPORT_ERRORS) {
+ trigger_error('Only reading is supported', E_USER_WARNING);
+ }
+ return false;
+ }
+
+ // 25 is length of "ole-chainedblockstream://"
+ parse_str(substr($path, 25), $this->params);
+ if (!isset($this->params['oleInstanceId'],
+ $this->params['blockId'],
+ $GLOBALS['_OLE_INSTANCES'][$this->params['oleInstanceId']])) {
+
+ if ($options & STREAM_REPORT_ERRORS) {
+ trigger_error('OLE stream not found', E_USER_WARNING);
+ }
+ return false;
+ }
+ $this->ole = $GLOBALS['_OLE_INSTANCES'][$this->params['oleInstanceId']];
+
+ $blockId = $this->params['blockId'];
+ $this->data = '';
+ if (isset($this->params['size']) &&
+ $this->params['size'] < $this->ole->bigBlockThreshold &&
+ $blockId != $this->ole->root->_StartBlock) {
+
+ // Block id refers to small blocks
+ $rootPos = $this->ole->_getBlockOffset($this->ole->root->_StartBlock);
+ while ($blockId != -2) {
+ $pos = $rootPos + $blockId * $this->ole->bigBlockSize;
+ $blockId = $this->ole->sbat[$blockId];
+ fseek($this->ole->_file_handle, $pos);
+ $this->data .= fread($this->ole->_file_handle, $this->ole->bigBlockSize);
+ }
+ } else {
+ // Block id refers to big blocks
+ while ($blockId != -2) {
+ $pos = $this->ole->_getBlockOffset($blockId);
+ fseek($this->ole->_file_handle, $pos);
+ $this->data .= fread($this->ole->_file_handle, $this->ole->bigBlockSize);
+ $blockId = $this->ole->bbat[$blockId];
+ }
+ }
+ if (isset($this->params['size'])) {
+ $this->data = substr($this->data, 0, $this->params['size']);
+ }
+
+ if ($options & STREAM_USE_PATH) {
+ $openedPath = $path;
+ }
+
+ return true;
+ }
+
+ /**
+ * Implements support for fclose().
+ * @return string
+ */
+ function stream_close()
+ {
+ $this->ole = null;
+ unset($GLOBALS['_OLE_INSTANCES']);
+ }
+
+ /**
+ * Implements support for fread(), fgets() etc.
+ * @param int maximum number of bytes to read
+ * @return string
+ */
+ function stream_read($count)
+ {
+ if ($this->stream_eof()) {
+ return false;
+ }
+ $s = substr($this->data, $this->pos, $count);
+ $this->pos += $count;
+ return $s;
+ }
+
+ /**
+ * Implements support for feof().
+ * @return bool TRUE if the file pointer is at EOF; otherwise FALSE
+ */
+ function stream_eof()
+ {
+ $eof = $this->pos >= strlen($this->data);
+ // Workaround for bug in PHP 5.0.x: http://bugs.php.net/27508
+ if (version_compare(PHP_VERSION, '5.0', '>=') &&
+ version_compare(PHP_VERSION, '5.1', '<')) {
+
+ $eof = !$eof;
+ }
+ return $eof;
+ }
+
+ /**
+ * Returns the position of the file pointer, i.e. its offset into the file
+ * stream. Implements support for ftell().
+ * @return int
+ */
+ function stream_tell()
+ {
+ return $this->pos;
+ }
+
+ /**
+ * Implements support for fseek().
+ * @param int byte offset
+ * @param int SEEK_SET, SEEK_CUR or SEEK_END
+ * @return bool
+ */
+ function stream_seek($offset, $whence)
+ {
+ if ($whence == SEEK_SET && $offset >= 0) {
+ $this->pos = $offset;
+ } elseif ($whence == SEEK_CUR && -$offset <= $this->pos) {
+ $this->pos += $offset;
+ } elseif ($whence == SEEK_END && -$offset <= sizeof($this->data)) {
+ $this->pos = strlen($this->data) + $offset;
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Implements support for fstat(). Currently the only supported field is
+ * "size".
+ * @return array
+ */
+ function stream_stat()
+ {
+ return array(
+ 'size' => strlen($this->data),
+ );
+ }
+
+ // Methods used by stream_wrapper_register() that are not implemented:
+ // bool stream_flush ( void )
+ // int stream_write ( string data )
+ // bool rename ( string path_from, string path_to )
+ // bool mkdir ( string path, int mode, int options )
+ // bool rmdir ( string path, int options )
+ // bool dir_opendir ( string path, int options )
+ // array url_stat ( string path, int flags )
+ // string dir_readdir ( void )
+ // bool dir_rewinddir ( void )
+ // bool dir_closedir ( void )
+}
+
+?>
diff --git a/vendor/library/Excel/phpxls/Console/Getopt.php b/vendor/library/Excel/phpxls/Console/Getopt.php
new file mode 100644
index 0000000..bb9d69c
--- /dev/null
+++ b/vendor/library/Excel/phpxls/Console/Getopt.php
@@ -0,0 +1,290 @@
+ |
+// +----------------------------------------------------------------------+
+//
+// $Id: Getopt.php,v 1.4 2007/06/12 14:58:56 cellog Exp $
+
+require_once 'PEAR.php';
+
+/**
+ * Command-line options parsing class.
+ *
+ * @author Andrei Zmievski
+ *
+ */
+class Console_Getopt {
+ /**
+ * Parses the command-line options.
+ *
+ * The first parameter to this function should be the list of command-line
+ * arguments without the leading reference to the running program.
+ *
+ * The second parameter is a string of allowed short options. Each of the
+ * option letters can be followed by a colon ':' to specify that the option
+ * requires an argument, or a double colon '::' to specify that the option
+ * takes an optional argument.
+ *
+ * The third argument is an optional array of allowed long options. The
+ * leading '--' should not be included in the option name. Options that
+ * require an argument should be followed by '=', and options that take an
+ * option argument should be followed by '=='.
+ *
+ * The return value is an array of two elements: the list of parsed
+ * options and the list of non-option command-line arguments. Each entry in
+ * the list of parsed options is a pair of elements - the first one
+ * specifies the option, and the second one specifies the option argument,
+ * if there was one.
+ *
+ * Long and short options can be mixed.
+ *
+ * Most of the semantics of this function are based on GNU getopt_long().
+ *
+ * @param array $args an array of command-line arguments
+ * @param string $short_options specifies the list of allowed short options
+ * @param array $long_options specifies the list of allowed long options
+ *
+ * @return array two-element array containing the list of parsed options and
+ * the non-option arguments
+ *
+ * @access public
+ *
+ */
+ function getopt2($args, $short_options, $long_options = null)
+ {
+ return Console_Getopt::doGetopt(2, $args, $short_options, $long_options);
+ }
+
+ /**
+ * This function expects $args to start with the script name (POSIX-style).
+ * Preserved for backwards compatibility.
+ * @see getopt2()
+ */
+ function getopt($args, $short_options, $long_options = null)
+ {
+ return Console_Getopt::doGetopt(1, $args, $short_options, $long_options);
+ }
+
+ /**
+ * The actual implementation of the argument parsing code.
+ */
+ function doGetopt($version, $args, $short_options, $long_options = null)
+ {
+ // in case you pass directly readPHPArgv() as the first arg
+ if (PEAR::isError($args)) {
+ return $args;
+ }
+ if (empty($args)) {
+ return array(array(), array());
+ }
+ $opts = array();
+ $non_opts = array();
+
+ settype($args, 'array');
+
+ if ($long_options) {
+ sort($long_options);
+ }
+
+ /*
+ * Preserve backwards compatibility with callers that relied on
+ * erroneous POSIX fix.
+ */
+ if ($version < 2) {
+ if (isset($args[0]{0}) && $args[0]{0} != '-') {
+ array_shift($args);
+ }
+ }
+
+ reset($args);
+ while (list($i, $arg) = each($args)) {
+
+ /* The special element '--' means explicit end of
+ options. Treat the rest of the arguments as non-options
+ and end the loop. */
+ if ($arg == '--') {
+ $non_opts = array_merge($non_opts, array_slice($args, $i + 1));
+ break;
+ }
+
+ if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) {
+ $non_opts = array_merge($non_opts, array_slice($args, $i));
+ break;
+ } elseif (strlen($arg) > 1 && $arg{1} == '-') {
+ $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args);
+ if (PEAR::isError($error))
+ return $error;
+ } elseif ($arg == '-') {
+ // - is stdin
+ $non_opts = array_merge($non_opts, array_slice($args, $i));
+ break;
+ } else {
+ $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args);
+ if (PEAR::isError($error))
+ return $error;
+ }
+ }
+
+ return array($opts, $non_opts);
+ }
+
+ /**
+ * @access private
+ *
+ */
+ function _parseShortOption($arg, $short_options, &$opts, &$args)
+ {
+ for ($i = 0; $i < strlen($arg); $i++) {
+ $opt = $arg{$i};
+ $opt_arg = null;
+
+ /* Try to find the short option in the specifier string. */
+ if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':')
+ {
+ return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt");
+ }
+
+ if (strlen($spec) > 1 && $spec{1} == ':') {
+ if (strlen($spec) > 2 && $spec{2} == ':') {
+ if ($i + 1 < strlen($arg)) {
+ /* Option takes an optional argument. Use the remainder of
+ the arg string if there is anything left. */
+ $opts[] = array($opt, substr($arg, $i + 1));
+ break;
+ }
+ } else {
+ /* Option requires an argument. Use the remainder of the arg
+ string if there is anything left. */
+ if ($i + 1 < strlen($arg)) {
+ $opts[] = array($opt, substr($arg, $i + 1));
+ break;
+ } else if (list(, $opt_arg) = each($args)) {
+ /* Else use the next argument. */;
+ if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) {
+ return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
+ }
+ } else {
+ return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
+ }
+ }
+ }
+
+ $opts[] = array($opt, $opt_arg);
+ }
+ }
+
+ /**
+ * @access private
+ *
+ */
+ function _isShortOpt($arg)
+ {
+ return strlen($arg) == 2 && $arg[0] == '-' && preg_match('/[a-zA-Z]/', $arg[1]);
+ }
+
+ /**
+ * @access private
+ *
+ */
+ function _isLongOpt($arg)
+ {
+ return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' &&
+ preg_match('/[a-zA-Z]+$/', substr($arg, 2));
+ }
+
+ /**
+ * @access private
+ *
+ */
+ function _parseLongOption($arg, $long_options, &$opts, &$args)
+ {
+ @list($opt, $opt_arg) = explode('=', $arg, 2);
+ $opt_len = strlen($opt);
+
+ for ($i = 0; $i < count($long_options); $i++) {
+ $long_opt = $long_options[$i];
+ $opt_start = substr($long_opt, 0, $opt_len);
+ $long_opt_name = str_replace('=', '', $long_opt);
+
+ /* Option doesn't match. Go on to the next one. */
+ if ($long_opt_name != $opt) {
+ continue;
+ }
+
+ $opt_rest = substr($long_opt, $opt_len);
+
+ /* Check that the options uniquely matches one of the allowed
+ options. */
+ if ($i + 1 < count($long_options)) {
+ $next_option_rest = substr($long_options[$i + 1], $opt_len);
+ } else {
+ $next_option_rest = '';
+ }
+ if ($opt_rest != '' && $opt{0} != '=' &&
+ $i + 1 < count($long_options) &&
+ $opt == substr($long_options[$i+1], 0, $opt_len) &&
+ $next_option_rest != '' &&
+ $next_option_rest{0} != '=') {
+ return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous");
+ }
+
+ if (substr($long_opt, -1) == '=') {
+ if (substr($long_opt, -2) != '==') {
+ /* Long option requires an argument.
+ Take the next argument if one wasn't specified. */;
+ if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) {
+ return PEAR::raiseError("Console_Getopt: option --$opt requires an argument");
+ }
+ if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) {
+ return PEAR::raiseError("Console_Getopt: option requires an argument --$opt");
+ }
+ }
+ } else if ($opt_arg) {
+ return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument");
+ }
+
+ $opts[] = array('--' . $opt, $opt_arg);
+ return;
+ }
+
+ return PEAR::raiseError("Console_Getopt: unrecognized option --$opt");
+ }
+
+ /**
+ * Safely read the $argv PHP array across different PHP configurations.
+ * Will take care on register_globals and register_argc_argv ini directives
+ *
+ * @access public
+ * @return mixed the $argv PHP array or PEAR error if not registered
+ */
+ function readPHPArgv()
+ {
+ global $argv;
+ if (!is_array($argv)) {
+ if (!@is_array($_SERVER['argv'])) {
+ if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
+ return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)");
+ }
+ return $GLOBALS['HTTP_SERVER_VARS']['argv'];
+ }
+ return $_SERVER['argv'];
+ }
+ return $argv;
+ }
+
+}
+
+?>
diff --git a/vendor/library/Excel/phpxls/ExcelWriter/BIFFwriter.php b/vendor/library/Excel/phpxls/ExcelWriter/BIFFwriter.php
new file mode 100644
index 0000000..0fd6daa
--- /dev/null
+++ b/vendor/library/Excel/phpxls/ExcelWriter/BIFFwriter.php
@@ -0,0 +1,241 @@
+
+*
+* The majority of this is _NOT_ my code. I simply ported it from the
+* PERL Spreadsheet::WriteExcel module.
+*
+* The author of the Spreadsheet::WriteExcel module is John McNamara
+*
+*
+* I _DO_ maintain this code, and John McNamara has nothing to do with the
+* porting of this code to PHP. Any questions directly related to this
+* class library should be directed to me.
+*
+* License Information:
+*
+* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
+* Copyright (c) 2002-2003 Xavier Noguer xnoguer@php.net
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+require_once 'PEAR.php';
+
+/**
+* Class for writing Excel BIFF records.
+*
+* From "MICROSOFT EXCEL BINARY FILE FORMAT" by Mark O'Brien (Microsoft Corporation):
+*
+* BIFF (BInary File Format) is the file format in which Excel documents are
+* saved on disk. A BIFF file is a complete description of an Excel document.
+* BIFF files consist of sequences of variable-length records. There are many
+* different types of BIFF records. For example, one record type describes a
+* formula entered into a cell; one describes the size and location of a
+* window into a document; another describes a picture format.
+*
+* @author Xavier Noguer
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+
+class Spreadsheet_Excel_Writer_BIFFwriter extends PEAR
+{
+ /**
+ * The BIFF/Excel version (5).
+ * @var integer
+ */
+ var $_BIFF_version = 0x0500;
+
+ /**
+ * The byte order of this architecture. 0 => little endian, 1 => big endian
+ * @var integer
+ */
+ var $_byte_order;
+
+ /**
+ * The string containing the data of the BIFF stream
+ * @var string
+ */
+ var $_data;
+
+ /**
+ * The size of the data in bytes. Should be the same as strlen($this->_data)
+ * @var integer
+ */
+ var $_datasize;
+
+ /**
+ * The maximun length for a BIFF record. See _addContinue()
+ * @var integer
+ * @see _addContinue()
+ */
+ var $_limit;
+
+ /**
+ * Constructor
+ *
+ * @access public
+ */
+
+ function __construct(){}
+
+ function Spreadsheet_Excel_Writer_BIFFwriter()
+ {
+ $this->_byte_order = '';
+ $this->_data = '';
+ $this->_datasize = 0;
+ $this->_limit = 2080;
+ // Set the byte order
+ $this->_setByteOrder();
+ }
+
+ /**
+ * Determine the byte order and store it as class data to avoid
+ * recalculating it for each call to new().
+ *
+ * @access private
+ */
+ function _setByteOrder()
+ {
+ // Check if "pack" gives the required IEEE 64bit float
+ $teststr = pack("d", 1.2345);
+ $number = pack("C8", 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F);
+ if ($number == $teststr) {
+ $byte_order = 0; // Little Endian
+ } elseif ($number == strrev($teststr)){
+ $byte_order = 1; // Big Endian
+ } else {
+ // Give up. I'll fix this in a later version.
+ return $this->raiseError("Required floating point format ".
+ "not supported on this platform.");
+ }
+ $this->_byte_order = $byte_order;
+ }
+
+ /**
+ * General storage function
+ *
+ * @param string $data binary data to prepend
+ * @access private
+ */
+ function _prepend($data)
+ {
+ if (strlen($data) > $this->_limit) {
+ $data = $this->_addContinue($data);
+ }
+ $this->_data = $data.$this->_data;
+ $this->_datasize += strlen($data);
+ }
+
+ /**
+ * General storage function
+ *
+ * @param string $data binary data to append
+ * @access private
+ */
+ function _append($data)
+ {
+ if (strlen($data) > $this->_limit) {
+ $data = $this->_addContinue($data);
+ }
+ $this->_data = $this->_data.$data;
+ $this->_datasize += strlen($data);
+ }
+
+ /**
+ * Writes Excel BOF record to indicate the beginning of a stream or
+ * sub-stream in the BIFF file.
+ *
+ * @param integer $type Type of BIFF file to write: 0x0005 Workbook,
+ * 0x0010 Worksheet.
+ * @access private
+ */
+ function _storeBof($type)
+ {
+ $record = 0x0809; // Record identifier
+
+ // According to the SDK $build and $year should be set to zero.
+ // However, this throws a warning in Excel 5. So, use magic numbers.
+ if ($this->_BIFF_version == 0x0500) {
+ $length = 0x0008;
+ $unknown = '';
+ $build = 0x096C;
+ $year = 0x07C9;
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $length = 0x0010;
+ $unknown = pack("VV", 0x00000041, 0x00000006); //unknown last 8 bytes for BIFF8
+ $build = 0x0DBB;
+ $year = 0x07CC;
+ }
+ $version = $this->_BIFF_version;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvv", $version, $type, $build, $year);
+ $this->_prepend($header . $data . $unknown);
+ }
+
+ /**
+ * Writes Excel EOF record to indicate the end of a BIFF stream.
+ *
+ * @access private
+ */
+ function _storeEof()
+ {
+ $record = 0x000A; // Record identifier
+ $length = 0x0000; // Number of bytes to follow
+ $header = pack("vv", $record, $length);
+ $this->_append($header);
+ }
+
+ /**
+ * Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In
+ * Excel 97 the limit is 8228 bytes. Records that are longer than these limits
+ * must be split up into CONTINUE blocks.
+ *
+ * This function takes a long BIFF record and inserts CONTINUE records as
+ * necessary.
+ *
+ * @param string $data The original binary data to be written
+ * @return string A very convenient string of continue blocks
+ * @access private
+ */
+ function _addContinue($data)
+ {
+ $limit = $this->_limit;
+ $record = 0x003C; // Record identifier
+
+ // The first 2080/8224 bytes remain intact. However, we have to change
+ // the length field of the record.
+ $tmp = substr($data, 0, 2).pack("v", $limit-4).substr($data, 4, $limit - 4);
+
+ $header = pack("vv", $record, $limit); // Headers for continue records
+
+ // Retrieve chunks of 2080/8224 bytes +4 for the header.
+ $data_length = strlen($data);
+ for ($i = $limit; $i < ($data_length - $limit); $i += $limit) {
+ $tmp .= $header;
+ $tmp .= substr($data, $i, $limit);
+ }
+
+ // Retrieve the last chunk of data
+ $header = pack("vv", $record, strlen($data) - $i);
+ $tmp .= $header;
+ $tmp .= substr($data, $i, strlen($data) - $i);
+
+ return $tmp;
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/ExcelWriter/Format.php b/vendor/library/Excel/phpxls/ExcelWriter/Format.php
new file mode 100644
index 0000000..adb823f
--- /dev/null
+++ b/vendor/library/Excel/phpxls/ExcelWriter/Format.php
@@ -0,0 +1,1102 @@
+
+*
+* The majority of this is _NOT_ my code. I simply ported it from the
+* PERL Spreadsheet::WriteExcel module.
+*
+* The author of the Spreadsheet::WriteExcel module is John McNamara
+*
+*
+* I _DO_ maintain this code, and John McNamara has nothing to do with the
+* porting of this code to PHP. Any questions directly related to this
+* class library should be directed to me.
+*
+* License Information:
+*
+* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
+* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+require_once 'PEAR.php';
+
+/**
+* Class for generating Excel XF records (formats)
+*
+* @author Xavier Noguer
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+
+class Spreadsheet_Excel_Writer_Format extends PEAR
+{
+ /**
+ * The index given by the workbook when creating a new format.
+ * @var integer
+ */
+ var $_xf_index;
+
+ /**
+ * Index to the FONT record.
+ * @var integer
+ */
+ var $font_index;
+
+ /**
+ * The font name (ASCII).
+ * @var string
+ */
+ var $_font_name;
+
+ /**
+ * Height of font (1/20 of a point)
+ * @var integer
+ */
+ var $_size;
+
+ /**
+ * Bold style
+ * @var integer
+ */
+ var $_bold;
+
+ /**
+ * Bit specifiying if the font is italic.
+ * @var integer
+ */
+ var $_italic;
+
+ /**
+ * Index to the cell's color
+ * @var integer
+ */
+ var $_color;
+
+ /**
+ * The text underline property
+ * @var integer
+ */
+ var $_underline;
+
+ /**
+ * Bit specifiying if the font has strikeout.
+ * @var integer
+ */
+ var $_font_strikeout;
+
+ /**
+ * Bit specifiying if the font has outline.
+ * @var integer
+ */
+ var $_font_outline;
+
+ /**
+ * Bit specifiying if the font has shadow.
+ * @var integer
+ */
+ var $_font_shadow;
+
+ /**
+ * 2 bytes specifiying the script type for the font.
+ * @var integer
+ */
+ var $_font_script;
+
+ /**
+ * Byte specifiying the font family.
+ * @var integer
+ */
+ var $_font_family;
+
+ /**
+ * Byte specifiying the font charset.
+ * @var integer
+ */
+ var $_font_charset;
+
+ /**
+ * An index (2 bytes) to a FORMAT record (number format).
+ * @var integer
+ */
+ var $_num_format;
+
+ /**
+ * Bit specifying if formulas are hidden.
+ * @var integer
+ */
+ var $_hidden;
+
+ /**
+ * Bit specifying if the cell is locked.
+ * @var integer
+ */
+ var $_locked;
+
+ /**
+ * The three bits specifying the text horizontal alignment.
+ * @var integer
+ */
+ var $_text_h_align;
+
+ /**
+ * Bit specifying if the text is wrapped at the right border.
+ * @var integer
+ */
+ var $_text_wrap;
+
+ /**
+ * The three bits specifying the text vertical alignment.
+ * @var integer
+ */
+ var $_text_v_align;
+
+ /**
+ * 1 bit, apparently not used.
+ * @var integer
+ */
+ var $_text_justlast;
+
+ /**
+ * The two bits specifying the text rotation.
+ * @var integer
+ */
+ var $_rotation;
+
+ /**
+ * The cell's foreground color.
+ * @var integer
+ */
+ var $_fg_color;
+
+ /**
+ * The cell's background color.
+ * @var integer
+ */
+ var $_bg_color;
+
+ /**
+ * The cell's background fill pattern.
+ * @var integer
+ */
+ var $_pattern;
+
+ /**
+ * Style of the bottom border of the cell
+ * @var integer
+ */
+ var $_bottom;
+
+ /**
+ * Color of the bottom border of the cell.
+ * @var integer
+ */
+ var $_bottom_color;
+
+ /**
+ * Style of the top border of the cell
+ * @var integer
+ */
+ var $_top;
+
+ /**
+ * Color of the top border of the cell.
+ * @var integer
+ */
+ var $_top_color;
+
+ /**
+ * Style of the left border of the cell
+ * @var integer
+ */
+ var $_left;
+
+ /**
+ * Color of the left border of the cell.
+ * @var integer
+ */
+ var $_left_color;
+
+ /**
+ * Style of the right border of the cell
+ * @var integer
+ */
+ var $_right;
+
+ /**
+ * Color of the right border of the cell.
+ * @var integer
+ */
+ var $_right_color;
+
+ /**
+ * Constructor
+ *
+ * @access private
+ * @param integer $index the XF index for the format.
+ * @param array $properties array with properties to be set on initialization.
+ */
+ function __construct($BIFF_version, $index = 0, $properties = array())
+ {
+ $this->_xf_index = $index;
+ $this->_BIFF_version = $BIFF_version;
+ $this->font_index = 0;
+ $this->_font_name = 'Arial';
+ $this->_size = 10;
+ $this->_bold = 0x0190;
+ $this->_italic = 0;
+ $this->_color = 0x7FFF;
+ $this->_underline = 0;
+ $this->_font_strikeout = 0;
+ $this->_font_outline = 0;
+ $this->_font_shadow = 0;
+ $this->_font_script = 0;
+ $this->_font_family = 0;
+ $this->_font_charset = 0;
+
+ $this->_num_format = 0;
+
+ $this->_hidden = 0;
+ $this->_locked = 0;
+
+ $this->_text_h_align = 0;
+ $this->_text_wrap = 0;
+ $this->_text_v_align = 2;
+ $this->_text_justlast = 0;
+ $this->_rotation = 0;
+
+ $this->_fg_color = 0x40;
+ $this->_bg_color = 0x41;
+
+ $this->_pattern = 0;
+
+ $this->_bottom = 0;
+ $this->_top = 0;
+ $this->_left = 0;
+ $this->_right = 0;
+ $this->_diag = 0;
+
+ $this->_bottom_color = 0x40;
+ $this->_top_color = 0x40;
+ $this->_left_color = 0x40;
+ $this->_right_color = 0x40;
+ $this->_diag_color = 0x40;
+
+ // Set properties passed to Spreadsheet_Excel_Writer_Workbook::addFormat()
+ foreach ($properties as $property => $value)
+ {
+ if (method_exists($this, 'set'.ucwords($property))) {
+ $method_name = 'set'.ucwords($property);
+ $this->$method_name($value);
+ }
+ }
+ }
+
+
+ /**
+ * Generate an Excel BIFF XF record (style or cell).
+ *
+ * @param string $style The type of the XF record ('style' or 'cell').
+ * @return string The XF record
+ */
+ function getXf($style)
+ {
+ // Set the type of the XF record and some of the attributes.
+ if ($style == 'style') {
+ $style = 0xFFF5;
+ } else {
+ $style = $this->_locked;
+ $style |= $this->_hidden << 1;
+ }
+
+ // Flags to indicate if attributes have been set.
+ $atr_num = ($this->_num_format != 0)?1:0;
+ $atr_fnt = ($this->font_index != 0)?1:0;
+ $atr_alc = ($this->_text_wrap)?1:0;
+ $atr_bdr = ($this->_bottom ||
+ $this->_top ||
+ $this->_left ||
+ $this->_right)?1:0;
+ $atr_pat = (($this->_fg_color != 0x40) ||
+ ($this->_bg_color != 0x41) ||
+ $this->_pattern)?1:0;
+ $atr_prot = $this->_locked | $this->_hidden;
+
+ // Zero the default border colour if the border has not been set.
+ if ($this->_bottom == 0) {
+ $this->_bottom_color = 0;
+ }
+ if ($this->_top == 0) {
+ $this->_top_color = 0;
+ }
+ if ($this->_right == 0) {
+ $this->_right_color = 0;
+ }
+ if ($this->_left == 0) {
+ $this->_left_color = 0;
+ }
+ if ($this->_diag == 0) {
+ $this->_diag_color = 0;
+ }
+
+ $record = 0x00E0; // Record identifier
+ if ($this->_BIFF_version == 0x0500) {
+ $length = 0x0010; // Number of bytes to follow
+ }
+ if ($this->_BIFF_version == 0x0600) {
+ $length = 0x0014;
+ }
+
+ $ifnt = $this->font_index; // Index to FONT record
+ $ifmt = $this->_num_format; // Index to FORMAT record
+ if ($this->_BIFF_version == 0x0500) {
+ $align = $this->_text_h_align; // Alignment
+ $align |= $this->_text_wrap << 3;
+ $align |= $this->_text_v_align << 4;
+ $align |= $this->_text_justlast << 7;
+ $align |= $this->_rotation << 8;
+ $align |= $atr_num << 10;
+ $align |= $atr_fnt << 11;
+ $align |= $atr_alc << 12;
+ $align |= $atr_bdr << 13;
+ $align |= $atr_pat << 14;
+ $align |= $atr_prot << 15;
+
+ $icv = $this->_fg_color; // fg and bg pattern colors
+ $icv |= $this->_bg_color << 7;
+
+ $fill = $this->_pattern; // Fill and border line style
+ $fill |= $this->_bottom << 6;
+ $fill |= $this->_bottom_color << 9;
+
+ $border1 = $this->_top; // Border line style and color
+ $border1 |= $this->_left << 3;
+ $border1 |= $this->_right << 6;
+ $border1 |= $this->_top_color << 9;
+
+ $border2 = $this->_left_color; // Border color
+ $border2 |= $this->_right_color << 7;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvvvvvv", $ifnt, $ifmt, $style, $align,
+ $icv, $fill,
+ $border1, $border2);
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $align = $this->_text_h_align; // Alignment
+ $align |= $this->_text_wrap << 3;
+ $align |= $this->_text_v_align << 4;
+ $align |= $this->_text_justlast << 7;
+
+ $used_attrib = $atr_num << 2;
+ $used_attrib |= $atr_fnt << 3;
+ $used_attrib |= $atr_alc << 4;
+ $used_attrib |= $atr_bdr << 5;
+ $used_attrib |= $atr_pat << 6;
+ $used_attrib |= $atr_prot << 7;
+
+ $icv = $this->_fg_color; // fg and bg pattern colors
+ $icv |= $this->_bg_color << 7;
+
+ $border1 = $this->_left; // Border line style and color
+ $border1 |= $this->_right << 4;
+ $border1 |= $this->_top << 8;
+ $border1 |= $this->_bottom << 12;
+ $border1 |= $this->_left_color << 16;
+ $border1 |= $this->_right_color << 23;
+ $diag_tl_to_rb = 0; // FIXME: add method
+ $diag_tr_to_lb = 0; // FIXME: add method
+ $border1 |= $diag_tl_to_rb << 30;
+ $border1 |= $diag_tr_to_lb << 31;
+
+ $border2 = $this->_top_color; // Border color
+ $border2 |= $this->_bottom_color << 7;
+ $border2 |= $this->_diag_color << 14;
+ $border2 |= $this->_diag << 21;
+ $border2 |= $this->_pattern << 26;
+
+ $header = pack("vv", $record, $length);
+
+ $rotation = 0x00;
+ $biff8_options = 0x00;
+ $data = pack("vvvC", $ifnt, $ifmt, $style, $align);
+ $data .= pack("CCC", $rotation, $biff8_options, $used_attrib);
+ $data .= pack("VVv", $border1, $border2, $icv);
+ }
+
+ return($header . $data);
+ }
+
+ /**
+ * Generate an Excel BIFF FONT record.
+ *
+ * @return string The FONT record
+ */
+ function getFont()
+ {
+ $dyHeight = $this->_size * 20; // Height of font (1/20 of a point)
+ $icv = $this->_color; // Index to color palette
+ $bls = $this->_bold; // Bold style
+ $sss = $this->_font_script; // Superscript/subscript
+ $uls = $this->_underline; // Underline
+ $bFamily = $this->_font_family; // Font family
+ $bCharSet = $this->_font_charset; // Character set
+ $encoding = 0; // TODO: Unicode support
+
+ $cch = strlen($this->_font_name); // Length of font name
+ $record = 0x31; // Record identifier
+ if ($this->_BIFF_version == 0x0500) {
+ $length = 0x0F + $cch; // Record length
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $length = 0x10 + $cch;
+ }
+ $reserved = 0x00; // Reserved
+ $grbit = 0x00; // Font attributes
+ if ($this->_italic) {
+ $grbit |= 0x02;
+ }
+ if ($this->_font_strikeout) {
+ $grbit |= 0x08;
+ }
+ if ($this->_font_outline) {
+ $grbit |= 0x10;
+ }
+ if ($this->_font_shadow) {
+ $grbit |= 0x20;
+ }
+
+ $header = pack("vv", $record, $length);
+ if ($this->_BIFF_version == 0x0500) {
+ $data = pack("vvvvvCCCCC", $dyHeight, $grbit, $icv, $bls,
+ $sss, $uls, $bFamily,
+ $bCharSet, $reserved, $cch);
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $data = pack("vvvvvCCCCCC", $dyHeight, $grbit, $icv, $bls,
+ $sss, $uls, $bFamily,
+ $bCharSet, $reserved, $cch, $encoding);
+ }
+ return($header . $data . $this->_font_name);
+ }
+
+ /**
+ * Returns a unique hash key for a font.
+ * Used by Spreadsheet_Excel_Writer_Workbook::_storeAllFonts()
+ *
+ * The elements that form the key are arranged to increase the probability of
+ * generating a unique key. Elements that hold a large range of numbers
+ * (eg. _color) are placed between two binary elements such as _italic
+ *
+ * @return string A key for this font
+ */
+ function getFontKey()
+ {
+ $key = "$this->_font_name$this->_size";
+ $key .= "$this->_font_script$this->_underline";
+ $key .= "$this->_font_strikeout$this->_bold$this->_font_outline";
+ $key .= "$this->_font_family$this->_font_charset";
+ $key .= "$this->_font_shadow$this->_color$this->_italic";
+ $key = str_replace(' ', '_', $key);
+ return ($key);
+ }
+
+ /**
+ * Returns the index used by Spreadsheet_Excel_Writer_Worksheet::_XF()
+ *
+ * @return integer The index for the XF record
+ */
+ function getXfIndex()
+ {
+ return($this->_xf_index);
+ }
+
+ /**
+ * Used in conjunction with the set_xxx_color methods to convert a color
+ * string into a number. Color range is 0..63 but we will restrict it
+ * to 8..63 to comply with Gnumeric. Colors 0..7 are repeated in 8..15.
+ *
+ * @access private
+ * @param string $name_color name of the color (i.e.: 'blue', 'red', etc..). Optional.
+ * @return integer The color index
+ */
+ function _getColor($name_color = '')
+ {
+ $colors = array(
+ 'aqua' => 0x0F,
+ 'cyan' => 0x0F,
+ 'black' => 0x08,
+ 'blue' => 0x0C,
+ 'brown' => 0x10,
+ 'magenta' => 0x0E,
+ 'fuchsia' => 0x0E,
+ 'gray' => 0x17,
+ 'grey' => 0x17,
+ 'green' => 0x11,
+ 'lime' => 0x0B,
+ 'navy' => 0x12,
+ 'orange' => 0x35,
+ 'purple' => 0x14,
+ 'red' => 0x0A,
+ 'silver' => 0x16,
+ 'white' => 0x09,
+ 'yellow' => 0x0D
+ );
+
+ // Return the default color, 0x7FFF, if undef,
+ if ($name_color == '') {
+ return(0x7FFF);
+ }
+
+ // or the color string converted to an integer,
+ if (isset($colors[$name_color])) {
+ return($colors[$name_color]);
+ }
+
+ // or the default color if string is unrecognised,
+ if (preg_match("/\D/",$name_color)) {
+ return(0x7FFF);
+ }
+
+ // or an index < 8 mapped into the correct range,
+ if ($name_color < 8) {
+ return($name_color + 8);
+ }
+
+ // or the default color if arg is outside range,
+ if ($name_color > 63) {
+ return(0x7FFF);
+ }
+
+ // or an integer in the valid range
+ return($name_color);
+ }
+
+ /**
+ * Set cell alignment.
+ *
+ * @access public
+ * @param string $location alignment for the cell ('left', 'right', etc...).
+ */
+ function setAlign($location)
+ {
+ if (preg_match("/\d/",$location)) {
+ return; // Ignore numbers
+ }
+
+ $location = strtolower($location);
+
+ if ($location == 'left') {
+ $this->_text_h_align = 1;
+ }
+ if ($location == 'centre') {
+ $this->_text_h_align = 2;
+ }
+ if ($location == 'center') {
+ $this->_text_h_align = 2;
+ }
+ if ($location == 'right') {
+ $this->_text_h_align = 3;
+ }
+ if ($location == 'fill') {
+ $this->_text_h_align = 4;
+ }
+ if ($location == 'justify') {
+ $this->_text_h_align = 5;
+ }
+ if ($location == 'merge') {
+ $this->_text_h_align = 6;
+ }
+ if ($location == 'equal_space') { // For T.K.
+ $this->_text_h_align = 7;
+ }
+ if ($location == 'top') {
+ $this->_text_v_align = 0;
+ }
+ if ($location == 'vcentre') {
+ $this->_text_v_align = 1;
+ }
+ if ($location == 'vcenter') {
+ $this->_text_v_align = 1;
+ }
+ if ($location == 'bottom') {
+ $this->_text_v_align = 2;
+ }
+ if ($location == 'vjustify') {
+ $this->_text_v_align = 3;
+ }
+ if ($location == 'vequal_space') { // For T.K.
+ $this->_text_v_align = 4;
+ }
+ }
+
+ /**
+ * Set cell horizontal alignment.
+ *
+ * @access public
+ * @param string $location alignment for the cell ('left', 'right', etc...).
+ */
+ function setHAlign($location)
+ {
+ if (preg_match("/\d/",$location)) {
+ return; // Ignore numbers
+ }
+
+ $location = strtolower($location);
+
+ if ($location == 'left') {
+ $this->_text_h_align = 1;
+ }
+ if ($location == 'centre') {
+ $this->_text_h_align = 2;
+ }
+ if ($location == 'center') {
+ $this->_text_h_align = 2;
+ }
+ if ($location == 'right') {
+ $this->_text_h_align = 3;
+ }
+ if ($location == 'fill') {
+ $this->_text_h_align = 4;
+ }
+ if ($location == 'justify') {
+ $this->_text_h_align = 5;
+ }
+ if ($location == 'merge') {
+ $this->_text_h_align = 6;
+ }
+ if ($location == 'equal_space') { // For T.K.
+ $this->_text_h_align = 7;
+ }
+ }
+
+ /**
+ * Set cell vertical alignment.
+ *
+ * @access public
+ * @param string $location alignment for the cell ('top', 'vleft', 'vright', etc...).
+ */
+ function setVAlign($location)
+ {
+ if (preg_match("/\d/",$location)) {
+ return; // Ignore numbers
+ }
+
+ $location = strtolower($location);
+
+ if ($location == 'top') {
+ $this->_text_v_align = 0;
+ }
+ if ($location == 'vcentre') {
+ $this->_text_v_align = 1;
+ }
+ if ($location == 'vcenter') {
+ $this->_text_v_align = 1;
+ }
+ if ($location == 'bottom') {
+ $this->_text_v_align = 2;
+ }
+ if ($location == 'vjustify') {
+ $this->_text_v_align = 3;
+ }
+ if ($location == 'vequal_space') { // For T.K.
+ $this->_text_v_align = 4;
+ }
+ }
+
+ /**
+ * This is an alias for the unintuitive setAlign('merge')
+ *
+ * @access public
+ */
+ function setMerge()
+ {
+ $this->setAlign('merge');
+ }
+
+ /**
+ * Sets the boldness of the text.
+ * Bold has a range 100..1000.
+ * 0 (400) is normal. 1 (700) is bold.
+ *
+ * @access public
+ * @param integer $weight Weight for the text, 0 maps to 400 (normal text),
+ 1 maps to 700 (bold text). Valid range is: 100-1000.
+ It's Optional, default is 1 (bold).
+ */
+ function setBold($weight = 1)
+ {
+ if ($weight == 1) {
+ $weight = 0x2BC; // Bold text
+ }
+ if ($weight == 0) {
+ $weight = 0x190; // Normal text
+ }
+ if ($weight < 0x064) {
+ $weight = 0x190; // Lower bound
+ }
+ if ($weight > 0x3E8) {
+ $weight = 0x190; // Upper bound
+ }
+ $this->_bold = $weight;
+ }
+
+
+ /************************************
+ * FUNCTIONS FOR SETTING CELLS BORDERS
+ */
+
+ /**
+ * Sets the width for the bottom border of the cell
+ *
+ * @access public
+ * @param integer $style style of the cell border. 1 => thin, 2 => thick.
+ */
+ function setBottom($style)
+ {
+ $this->_bottom = $style;
+ }
+
+ /**
+ * Sets the width for the top border of the cell
+ *
+ * @access public
+ * @param integer $style style of the cell top border. 1 => thin, 2 => thick.
+ */
+ function setTop($style)
+ {
+ $this->_top = $style;
+ }
+
+ /**
+ * Sets the width for the left border of the cell
+ *
+ * @access public
+ * @param integer $style style of the cell left border. 1 => thin, 2 => thick.
+ */
+ function setLeft($style)
+ {
+ $this->_left = $style;
+ }
+
+ /**
+ * Sets the width for the right border of the cell
+ *
+ * @access public
+ * @param integer $style style of the cell right border. 1 => thin, 2 => thick.
+ */
+ function setRight($style)
+ {
+ $this->_right = $style;
+ }
+
+
+ /**
+ * Set cells borders to the same style
+ *
+ * @access public
+ * @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick.
+ */
+ function setBorder($style)
+ {
+ $this->setBottom($style);
+ $this->setTop($style);
+ $this->setLeft($style);
+ $this->setRight($style);
+ }
+
+
+ /*******************************************
+ * FUNCTIONS FOR SETTING CELLS BORDERS COLORS
+ */
+
+ /**
+ * Sets all the cell's borders to the same color
+ *
+ * @access public
+ * @param mixed $color The color we are setting. Either a string (like 'blue'),
+ * or an integer (range is [8...63]).
+ */
+ function setBorderColor($color)
+ {
+ $this->setBottomColor($color);
+ $this->setTopColor($color);
+ $this->setLeftColor($color);
+ $this->setRightColor($color);
+ }
+
+ /**
+ * Sets the cell's bottom border color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setBottomColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_bottom_color = $value;
+ }
+
+ /**
+ * Sets the cell's top border color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setTopColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_top_color = $value;
+ }
+
+ /**
+ * Sets the cell's left border color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setLeftColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_left_color = $value;
+ }
+
+ /**
+ * Sets the cell's right border color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setRightColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_right_color = $value;
+ }
+
+
+ /**
+ * Sets the cell's foreground color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setFgColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_fg_color = $value;
+ if ($this->_pattern == 0) { // force color to be seen
+ $this->_pattern = 1;
+ }
+ }
+
+ /**
+ * Sets the cell's background color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setBgColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_bg_color = $value;
+ if ($this->_pattern == 0) { // force color to be seen
+ $this->_pattern = 1;
+ }
+ }
+
+ /**
+ * Sets the cell's color
+ *
+ * @access public
+ * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
+ */
+ function setColor($color)
+ {
+ $value = $this->_getColor($color);
+ $this->_color = $value;
+ }
+
+ /**
+ * Sets the fill pattern attribute of a cell
+ *
+ * @access public
+ * @param integer $arg Optional. Defaults to 1. Meaningful values are: 0-18,
+ * 0 meaning no background.
+ */
+ function setPattern($arg = 1)
+ {
+ $this->_pattern = $arg;
+ }
+
+ /**
+ * Sets the underline of the text
+ *
+ * @access public
+ * @param integer $underline The value for underline. Possible values are:
+ * 1 => underline, 2 => double underline.
+ */
+ function setUnderline($underline)
+ {
+ $this->_underline = $underline;
+ }
+
+ /**
+ * Sets the font style as italic
+ *
+ * @access public
+ */
+ function setItalic()
+ {
+ $this->_italic = 1;
+ }
+
+ /**
+ * Sets the font size
+ *
+ * @access public
+ * @param integer $size The font size (in pixels I think).
+ */
+ function setSize($size)
+ {
+ $this->_size = $size;
+ }
+
+ /**
+ * Sets text wrapping
+ *
+ * @access public
+ */
+ function setTextWrap()
+ {
+ $this->_text_wrap = 1;
+ }
+
+ /**
+ * Sets the orientation of the text
+ *
+ * @access public
+ * @param integer $angle The rotation angle for the text (clockwise). Possible
+ values are: 0, 90, 270 and -1 for stacking top-to-bottom.
+ */
+ function setTextRotation($angle)
+ {
+ switch ($angle)
+ {
+ case 0:
+ $this->_rotation = 0;
+ break;
+ case 90:
+ $this->_rotation = 3;
+ break;
+ case 270:
+ $this->_rotation = 2;
+ break;
+ case -1:
+ $this->_rotation = 1;
+ break;
+ default :
+ return $this->raiseError("Invalid value for angle.".
+ " Possible values are: 0, 90, 270 and -1 ".
+ "for stacking top-to-bottom.");
+ $this->_rotation = 0;
+ break;
+ }
+ }
+
+ /**
+ * Sets the numeric format.
+ * It can be date, time, currency, etc...
+ *
+ * @access public
+ * @param integer $num_format The numeric format.
+ */
+ function setNumFormat($num_format)
+ {
+ $this->_num_format = $num_format;
+ }
+
+ /**
+ * Sets font as strikeout.
+ *
+ * @access public
+ */
+ function setStrikeOut()
+ {
+ $this->_font_strikeout = 1;
+ }
+
+ /**
+ * Sets outlining for a font.
+ *
+ * @access public
+ */
+ function setOutLine()
+ {
+ $this->_font_outline = 1;
+ }
+
+ /**
+ * Sets font as shadow.
+ *
+ * @access public
+ */
+ function setShadow()
+ {
+ $this->_font_shadow = 1;
+ }
+
+ /**
+ * Sets the script type of the text
+ *
+ * @access public
+ * @param integer $script The value for script type. Possible values are:
+ * 1 => superscript, 2 => subscript.
+ */
+ function setScript($script)
+ {
+ $this->_font_script = $script;
+ }
+
+ /**
+ * Locks a cell.
+ *
+ * @access public
+ */
+ function setLocked()
+ {
+ $this->_locked = 1;
+ }
+
+ /**
+ * Unlocks a cell. Useful for unprotecting particular cells of a protected sheet.
+ *
+ * @access public
+ */
+ function setUnLocked()
+ {
+ $this->_locked = 0;
+ }
+
+ /**
+ * Sets the font family name.
+ *
+ * @access public
+ * @param string $fontfamily The font family name. Possible values are:
+ * 'Times New Roman', 'Arial', 'Courier'.
+ */
+ function setFontFamily($font_family)
+ {
+ $this->_font_name = $font_family;
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/ExcelWriter/Parser.php b/vendor/library/Excel/phpxls/ExcelWriter/Parser.php
new file mode 100644
index 0000000..834da79
--- /dev/null
+++ b/vendor/library/Excel/phpxls/ExcelWriter/Parser.php
@@ -0,0 +1,1689 @@
+"
+*/
+define('SPREADSHEET_EXCEL_WRITER_GT', ">");
+
+/**
+* @const SPREADSHEET_EXCEL_WRITER_LT token identifier for character "<"
+*/
+define('SPREADSHEET_EXCEL_WRITER_LT', "<");
+
+/**
+* @const SPREADSHEET_EXCEL_WRITER_LE token identifier for character "<="
+*/
+define('SPREADSHEET_EXCEL_WRITER_LE', "<=");
+
+/**
+* @const SPREADSHEET_EXCEL_WRITER_GE token identifier for character ">="
+*/
+define('SPREADSHEET_EXCEL_WRITER_GE', ">=");
+
+/**
+* @const SPREADSHEET_EXCEL_WRITER_EQ token identifier for character "="
+*/
+define('SPREADSHEET_EXCEL_WRITER_EQ', "=");
+
+/**
+* @const SPREADSHEET_EXCEL_WRITER_NE token identifier for character "<>"
+*/
+define('SPREADSHEET_EXCEL_WRITER_NE', "<>");
+
+
+require_once 'PEAR.php';
+
+/**
+* Class for parsing Excel formulas
+*
+* @author Xavier Noguer
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+
+class Spreadsheet_Excel_Writer_Parser extends PEAR
+{
+ /**
+ * The index of the character we are currently looking at
+ * @var integer
+ */
+ var $_current_char;
+
+ /**
+ * The token we are working on.
+ * @var string
+ */
+ var $_current_token;
+
+ /**
+ * The formula to parse
+ * @var string
+ */
+ var $_formula;
+
+ /**
+ * The character ahead of the current char
+ * @var string
+ */
+ var $_lookahead;
+
+ /**
+ * The parse tree to be generated
+ * @var string
+ */
+ var $_parse_tree;
+
+ /**
+ * The byte order. 1 => big endian, 0 => little endian.
+ * @var integer
+ */
+ var $_byte_order;
+
+ /**
+ * Array of external sheets
+ * @var array
+ */
+ var $_ext_sheets;
+
+ /**
+ * Array of sheet references in the form of REF structures
+ * @var array
+ */
+ var $_references;
+
+ /**
+ * The BIFF version for the workbook
+ * @var integer
+ */
+ var $_BIFF_version;
+
+ /**
+ * The class constructor
+ *
+ * @param integer $byte_order The byte order (Little endian or Big endian) of the architecture
+ (optional). 1 => big endian, 0 (default) little endian.
+ */
+ function __construct($byte_order, $biff_version)
+ {
+ $this->_current_char = 0;
+ $this->_BIFF_version = $biff_version;
+ $this->_current_token = ''; // The token we are working on.
+ $this->_formula = ''; // The formula to parse.
+ $this->_lookahead = ''; // The character ahead of the current char.
+ $this->_parse_tree = ''; // The parse tree to be generated.
+ $this->_initializeHashes(); // Initialize the hashes: ptg's and function's ptg's
+ $this->_byte_order = $byte_order; // Little Endian or Big Endian
+ $this->_ext_sheets = array();
+ $this->_references = array();
+ }
+
+ /**
+ * Initialize the ptg and function hashes.
+ *
+ * @access private
+ */
+ function _initializeHashes()
+ {
+ // The Excel ptg indices
+ $this->ptg = array(
+ 'ptgExp' => 0x01,
+ 'ptgTbl' => 0x02,
+ 'ptgAdd' => 0x03,
+ 'ptgSub' => 0x04,
+ 'ptgMul' => 0x05,
+ 'ptgDiv' => 0x06,
+ 'ptgPower' => 0x07,
+ 'ptgConcat' => 0x08,
+ 'ptgLT' => 0x09,
+ 'ptgLE' => 0x0A,
+ 'ptgEQ' => 0x0B,
+ 'ptgGE' => 0x0C,
+ 'ptgGT' => 0x0D,
+ 'ptgNE' => 0x0E,
+ 'ptgIsect' => 0x0F,
+ 'ptgUnion' => 0x10,
+ 'ptgRange' => 0x11,
+ 'ptgUplus' => 0x12,
+ 'ptgUminus' => 0x13,
+ 'ptgPercent' => 0x14,
+ 'ptgParen' => 0x15,
+ 'ptgMissArg' => 0x16,
+ 'ptgStr' => 0x17,
+ 'ptgAttr' => 0x19,
+ 'ptgSheet' => 0x1A,
+ 'ptgEndSheet' => 0x1B,
+ 'ptgErr' => 0x1C,
+ 'ptgBool' => 0x1D,
+ 'ptgInt' => 0x1E,
+ 'ptgNum' => 0x1F,
+ 'ptgArray' => 0x20,
+ 'ptgFunc' => 0x21,
+ 'ptgFuncVar' => 0x22,
+ 'ptgName' => 0x23,
+ 'ptgRef' => 0x24,
+ 'ptgArea' => 0x25,
+ 'ptgMemArea' => 0x26,
+ 'ptgMemErr' => 0x27,
+ 'ptgMemNoMem' => 0x28,
+ 'ptgMemFunc' => 0x29,
+ 'ptgRefErr' => 0x2A,
+ 'ptgAreaErr' => 0x2B,
+ 'ptgRefN' => 0x2C,
+ 'ptgAreaN' => 0x2D,
+ 'ptgMemAreaN' => 0x2E,
+ 'ptgMemNoMemN' => 0x2F,
+ 'ptgNameX' => 0x39,
+ 'ptgRef3d' => 0x3A,
+ 'ptgArea3d' => 0x3B,
+ 'ptgRefErr3d' => 0x3C,
+ 'ptgAreaErr3d' => 0x3D,
+ 'ptgArrayV' => 0x40,
+ 'ptgFuncV' => 0x41,
+ 'ptgFuncVarV' => 0x42,
+ 'ptgNameV' => 0x43,
+ 'ptgRefV' => 0x44,
+ 'ptgAreaV' => 0x45,
+ 'ptgMemAreaV' => 0x46,
+ 'ptgMemErrV' => 0x47,
+ 'ptgMemNoMemV' => 0x48,
+ 'ptgMemFuncV' => 0x49,
+ 'ptgRefErrV' => 0x4A,
+ 'ptgAreaErrV' => 0x4B,
+ 'ptgRefNV' => 0x4C,
+ 'ptgAreaNV' => 0x4D,
+ 'ptgMemAreaNV' => 0x4E,
+ 'ptgMemNoMemN' => 0x4F,
+ 'ptgFuncCEV' => 0x58,
+ 'ptgNameXV' => 0x59,
+ 'ptgRef3dV' => 0x5A,
+ 'ptgArea3dV' => 0x5B,
+ 'ptgRefErr3dV' => 0x5C,
+ 'ptgAreaErr3d' => 0x5D,
+ 'ptgArrayA' => 0x60,
+ 'ptgFuncA' => 0x61,
+ 'ptgFuncVarA' => 0x62,
+ 'ptgNameA' => 0x63,
+ 'ptgRefA' => 0x64,
+ 'ptgAreaA' => 0x65,
+ 'ptgMemAreaA' => 0x66,
+ 'ptgMemErrA' => 0x67,
+ 'ptgMemNoMemA' => 0x68,
+ 'ptgMemFuncA' => 0x69,
+ 'ptgRefErrA' => 0x6A,
+ 'ptgAreaErrA' => 0x6B,
+ 'ptgRefNA' => 0x6C,
+ 'ptgAreaNA' => 0x6D,
+ 'ptgMemAreaNA' => 0x6E,
+ 'ptgMemNoMemN' => 0x6F,
+ 'ptgFuncCEA' => 0x78,
+ 'ptgNameXA' => 0x79,
+ 'ptgRef3dA' => 0x7A,
+ 'ptgArea3dA' => 0x7B,
+ 'ptgRefErr3dA' => 0x7C,
+ 'ptgAreaErr3d' => 0x7D
+ );
+
+ // Thanks to Michael Meeks and Gnumeric for the initial arg values.
+ //
+ // The following hash was generated by "function_locale.pl" in the distro.
+ // Refer to function_locale.pl for non-English function names.
+ //
+ // The array elements are as follow:
+ // ptg: The Excel function ptg code.
+ // args: The number of arguments that the function takes:
+ // >=0 is a fixed number of arguments.
+ // -1 is a variable number of arguments.
+ // class: The reference, value or array class of the function args.
+ // vol: The function is volatile.
+ //
+ $this->_functions = array(
+ // function ptg args class vol
+ 'COUNT' => array( 0, -1, 0, 0 ),
+ 'IF' => array( 1, -1, 1, 0 ),
+ 'ISNA' => array( 2, 1, 1, 0 ),
+ 'ISERROR' => array( 3, 1, 1, 0 ),
+ 'SUM' => array( 4, -1, 0, 0 ),
+ 'AVERAGE' => array( 5, -1, 0, 0 ),
+ 'MIN' => array( 6, -1, 0, 0 ),
+ 'MAX' => array( 7, -1, 0, 0 ),
+ 'ROW' => array( 8, -1, 0, 0 ),
+ 'COLUMN' => array( 9, -1, 0, 0 ),
+ 'NA' => array( 10, 0, 0, 0 ),
+ 'NPV' => array( 11, -1, 1, 0 ),
+ 'STDEV' => array( 12, -1, 0, 0 ),
+ 'DOLLAR' => array( 13, -1, 1, 0 ),
+ 'FIXED' => array( 14, -1, 1, 0 ),
+ 'SIN' => array( 15, 1, 1, 0 ),
+ 'COS' => array( 16, 1, 1, 0 ),
+ 'TAN' => array( 17, 1, 1, 0 ),
+ 'ATAN' => array( 18, 1, 1, 0 ),
+ 'PI' => array( 19, 0, 1, 0 ),
+ 'SQRT' => array( 20, 1, 1, 0 ),
+ 'EXP' => array( 21, 1, 1, 0 ),
+ 'LN' => array( 22, 1, 1, 0 ),
+ 'LOG10' => array( 23, 1, 1, 0 ),
+ 'ABS' => array( 24, 1, 1, 0 ),
+ 'INT' => array( 25, 1, 1, 0 ),
+ 'SIGN' => array( 26, 1, 1, 0 ),
+ 'ROUND' => array( 27, 2, 1, 0 ),
+ 'LOOKUP' => array( 28, -1, 0, 0 ),
+ 'INDEX' => array( 29, -1, 0, 1 ),
+ 'REPT' => array( 30, 2, 1, 0 ),
+ 'MID' => array( 31, 3, 1, 0 ),
+ 'LEN' => array( 32, 1, 1, 0 ),
+ 'VALUE' => array( 33, 1, 1, 0 ),
+ 'TRUE' => array( 34, 0, 1, 0 ),
+ 'FALSE' => array( 35, 0, 1, 0 ),
+ 'AND' => array( 36, -1, 0, 0 ),
+ 'OR' => array( 37, -1, 0, 0 ),
+ 'NOT' => array( 38, 1, 1, 0 ),
+ 'MOD' => array( 39, 2, 1, 0 ),
+ 'DCOUNT' => array( 40, 3, 0, 0 ),
+ 'DSUM' => array( 41, 3, 0, 0 ),
+ 'DAVERAGE' => array( 42, 3, 0, 0 ),
+ 'DMIN' => array( 43, 3, 0, 0 ),
+ 'DMAX' => array( 44, 3, 0, 0 ),
+ 'DSTDEV' => array( 45, 3, 0, 0 ),
+ 'VAR' => array( 46, -1, 0, 0 ),
+ 'DVAR' => array( 47, 3, 0, 0 ),
+ 'TEXT' => array( 48, 2, 1, 0 ),
+ 'LINEST' => array( 49, -1, 0, 0 ),
+ 'TREND' => array( 50, -1, 0, 0 ),
+ 'LOGEST' => array( 51, -1, 0, 0 ),
+ 'GROWTH' => array( 52, -1, 0, 0 ),
+ 'PV' => array( 56, -1, 1, 0 ),
+ 'FV' => array( 57, -1, 1, 0 ),
+ 'NPER' => array( 58, -1, 1, 0 ),
+ 'PMT' => array( 59, -1, 1, 0 ),
+ 'RATE' => array( 60, -1, 1, 0 ),
+ 'MIRR' => array( 61, 3, 0, 0 ),
+ 'IRR' => array( 62, -1, 0, 0 ),
+ 'RAND' => array( 63, 0, 1, 1 ),
+ 'MATCH' => array( 64, -1, 0, 0 ),
+ 'DATE' => array( 65, 3, 1, 0 ),
+ 'TIME' => array( 66, 3, 1, 0 ),
+ 'DAY' => array( 67, 1, 1, 0 ),
+ 'MONTH' => array( 68, 1, 1, 0 ),
+ 'YEAR' => array( 69, 1, 1, 0 ),
+ 'WEEKDAY' => array( 70, -1, 1, 0 ),
+ 'HOUR' => array( 71, 1, 1, 0 ),
+ 'MINUTE' => array( 72, 1, 1, 0 ),
+ 'SECOND' => array( 73, 1, 1, 0 ),
+ 'NOW' => array( 74, 0, 1, 1 ),
+ 'AREAS' => array( 75, 1, 0, 1 ),
+ 'ROWS' => array( 76, 1, 0, 1 ),
+ 'COLUMNS' => array( 77, 1, 0, 1 ),
+ 'OFFSET' => array( 78, -1, 0, 1 ),
+ 'SEARCH' => array( 82, -1, 1, 0 ),
+ 'TRANSPOSE' => array( 83, 1, 1, 0 ),
+ 'TYPE' => array( 86, 1, 1, 0 ),
+ 'ATAN2' => array( 97, 2, 1, 0 ),
+ 'ASIN' => array( 98, 1, 1, 0 ),
+ 'ACOS' => array( 99, 1, 1, 0 ),
+ 'CHOOSE' => array( 100, -1, 1, 0 ),
+ 'HLOOKUP' => array( 101, -1, 0, 0 ),
+ 'VLOOKUP' => array( 102, -1, 0, 0 ),
+ 'ISREF' => array( 105, 1, 0, 0 ),
+ 'LOG' => array( 109, -1, 1, 0 ),
+ 'CHAR' => array( 111, 1, 1, 0 ),
+ 'LOWER' => array( 112, 1, 1, 0 ),
+ 'UPPER' => array( 113, 1, 1, 0 ),
+ 'PROPER' => array( 114, 1, 1, 0 ),
+ 'LEFT' => array( 115, -1, 1, 0 ),
+ 'RIGHT' => array( 116, -1, 1, 0 ),
+ 'EXACT' => array( 117, 2, 1, 0 ),
+ 'TRIM' => array( 118, 1, 1, 0 ),
+ 'REPLACE' => array( 119, 4, 1, 0 ),
+ 'SUBSTITUTE' => array( 120, -1, 1, 0 ),
+ 'CODE' => array( 121, 1, 1, 0 ),
+ 'FIND' => array( 124, -1, 1, 0 ),
+ 'CELL' => array( 125, -1, 0, 1 ),
+ 'ISERR' => array( 126, 1, 1, 0 ),
+ 'ISTEXT' => array( 127, 1, 1, 0 ),
+ 'ISNUMBER' => array( 128, 1, 1, 0 ),
+ 'ISBLANK' => array( 129, 1, 1, 0 ),
+ 'T' => array( 130, 1, 0, 0 ),
+ 'N' => array( 131, 1, 0, 0 ),
+ 'DATEVALUE' => array( 140, 1, 1, 0 ),
+ 'TIMEVALUE' => array( 141, 1, 1, 0 ),
+ 'SLN' => array( 142, 3, 1, 0 ),
+ 'SYD' => array( 143, 4, 1, 0 ),
+ 'DDB' => array( 144, -1, 1, 0 ),
+ 'INDIRECT' => array( 148, -1, 1, 1 ),
+ 'CALL' => array( 150, -1, 1, 0 ),
+ 'CLEAN' => array( 162, 1, 1, 0 ),
+ 'MDETERM' => array( 163, 1, 2, 0 ),
+ 'MINVERSE' => array( 164, 1, 2, 0 ),
+ 'MMULT' => array( 165, 2, 2, 0 ),
+ 'IPMT' => array( 167, -1, 1, 0 ),
+ 'PPMT' => array( 168, -1, 1, 0 ),
+ 'COUNTA' => array( 169, -1, 0, 0 ),
+ 'PRODUCT' => array( 183, -1, 0, 0 ),
+ 'FACT' => array( 184, 1, 1, 0 ),
+ 'DPRODUCT' => array( 189, 3, 0, 0 ),
+ 'ISNONTEXT' => array( 190, 1, 1, 0 ),
+ 'STDEVP' => array( 193, -1, 0, 0 ),
+ 'VARP' => array( 194, -1, 0, 0 ),
+ 'DSTDEVP' => array( 195, 3, 0, 0 ),
+ 'DVARP' => array( 196, 3, 0, 0 ),
+ 'TRUNC' => array( 197, -1, 1, 0 ),
+ 'ISLOGICAL' => array( 198, 1, 1, 0 ),
+ 'DCOUNTA' => array( 199, 3, 0, 0 ),
+ 'ROUNDUP' => array( 212, 2, 1, 0 ),
+ 'ROUNDDOWN' => array( 213, 2, 1, 0 ),
+ 'RANK' => array( 216, -1, 0, 0 ),
+ 'ADDRESS' => array( 219, -1, 1, 0 ),
+ 'DAYS360' => array( 220, -1, 1, 0 ),
+ 'TODAY' => array( 221, 0, 1, 1 ),
+ 'VDB' => array( 222, -1, 1, 0 ),
+ 'MEDIAN' => array( 227, -1, 0, 0 ),
+ 'SUMPRODUCT' => array( 228, -1, 2, 0 ),
+ 'SINH' => array( 229, 1, 1, 0 ),
+ 'COSH' => array( 230, 1, 1, 0 ),
+ 'TANH' => array( 231, 1, 1, 0 ),
+ 'ASINH' => array( 232, 1, 1, 0 ),
+ 'ACOSH' => array( 233, 1, 1, 0 ),
+ 'ATANH' => array( 234, 1, 1, 0 ),
+ 'DGET' => array( 235, 3, 0, 0 ),
+ 'INFO' => array( 244, 1, 1, 1 ),
+ 'DB' => array( 247, -1, 1, 0 ),
+ 'FREQUENCY' => array( 252, 2, 0, 0 ),
+ 'ERROR.TYPE' => array( 261, 1, 1, 0 ),
+ 'REGISTER.ID' => array( 267, -1, 1, 0 ),
+ 'AVEDEV' => array( 269, -1, 0, 0 ),
+ 'BETADIST' => array( 270, -1, 1, 0 ),
+ 'GAMMALN' => array( 271, 1, 1, 0 ),
+ 'BETAINV' => array( 272, -1, 1, 0 ),
+ 'BINOMDIST' => array( 273, 4, 1, 0 ),
+ 'CHIDIST' => array( 274, 2, 1, 0 ),
+ 'CHIINV' => array( 275, 2, 1, 0 ),
+ 'COMBIN' => array( 276, 2, 1, 0 ),
+ 'CONFIDENCE' => array( 277, 3, 1, 0 ),
+ 'CRITBINOM' => array( 278, 3, 1, 0 ),
+ 'EVEN' => array( 279, 1, 1, 0 ),
+ 'EXPONDIST' => array( 280, 3, 1, 0 ),
+ 'FDIST' => array( 281, 3, 1, 0 ),
+ 'FINV' => array( 282, 3, 1, 0 ),
+ 'FISHER' => array( 283, 1, 1, 0 ),
+ 'FISHERINV' => array( 284, 1, 1, 0 ),
+ 'FLOOR' => array( 285, 2, 1, 0 ),
+ 'GAMMADIST' => array( 286, 4, 1, 0 ),
+ 'GAMMAINV' => array( 287, 3, 1, 0 ),
+ 'CEILING' => array( 288, 2, 1, 0 ),
+ 'HYPGEOMDIST' => array( 289, 4, 1, 0 ),
+ 'LOGNORMDIST' => array( 290, 3, 1, 0 ),
+ 'LOGINV' => array( 291, 3, 1, 0 ),
+ 'NEGBINOMDIST' => array( 292, 3, 1, 0 ),
+ 'NORMDIST' => array( 293, 4, 1, 0 ),
+ 'NORMSDIST' => array( 294, 1, 1, 0 ),
+ 'NORMINV' => array( 295, 3, 1, 0 ),
+ 'NORMSINV' => array( 296, 1, 1, 0 ),
+ 'STANDARDIZE' => array( 297, 3, 1, 0 ),
+ 'ODD' => array( 298, 1, 1, 0 ),
+ 'PERMUT' => array( 299, 2, 1, 0 ),
+ 'POISSON' => array( 300, 3, 1, 0 ),
+ 'TDIST' => array( 301, 3, 1, 0 ),
+ 'WEIBULL' => array( 302, 4, 1, 0 ),
+ 'SUMXMY2' => array( 303, 2, 2, 0 ),
+ 'SUMX2MY2' => array( 304, 2, 2, 0 ),
+ 'SUMX2PY2' => array( 305, 2, 2, 0 ),
+ 'CHITEST' => array( 306, 2, 2, 0 ),
+ 'CORREL' => array( 307, 2, 2, 0 ),
+ 'COVAR' => array( 308, 2, 2, 0 ),
+ 'FORECAST' => array( 309, 3, 2, 0 ),
+ 'FTEST' => array( 310, 2, 2, 0 ),
+ 'INTERCEPT' => array( 311, 2, 2, 0 ),
+ 'PEARSON' => array( 312, 2, 2, 0 ),
+ 'RSQ' => array( 313, 2, 2, 0 ),
+ 'STEYX' => array( 314, 2, 2, 0 ),
+ 'SLOPE' => array( 315, 2, 2, 0 ),
+ 'TTEST' => array( 316, 4, 2, 0 ),
+ 'PROB' => array( 317, -1, 2, 0 ),
+ 'DEVSQ' => array( 318, -1, 0, 0 ),
+ 'GEOMEAN' => array( 319, -1, 0, 0 ),
+ 'HARMEAN' => array( 320, -1, 0, 0 ),
+ 'SUMSQ' => array( 321, -1, 0, 0 ),
+ 'KURT' => array( 322, -1, 0, 0 ),
+ 'SKEW' => array( 323, -1, 0, 0 ),
+ 'ZTEST' => array( 324, -1, 0, 0 ),
+ 'LARGE' => array( 325, 2, 0, 0 ),
+ 'SMALL' => array( 326, 2, 0, 0 ),
+ 'QUARTILE' => array( 327, 2, 0, 0 ),
+ 'PERCENTILE' => array( 328, 2, 0, 0 ),
+ 'PERCENTRANK' => array( 329, -1, 0, 0 ),
+ 'MODE' => array( 330, -1, 2, 0 ),
+ 'TRIMMEAN' => array( 331, 2, 0, 0 ),
+ 'TINV' => array( 332, 2, 1, 0 ),
+ 'CONCATENATE' => array( 336, -1, 1, 0 ),
+ 'POWER' => array( 337, 2, 1, 0 ),
+ 'RADIANS' => array( 342, 1, 1, 0 ),
+ 'DEGREES' => array( 343, 1, 1, 0 ),
+ 'SUBTOTAL' => array( 344, -1, 0, 0 ),
+ 'SUMIF' => array( 345, -1, 0, 0 ),
+ 'COUNTIF' => array( 346, 2, 0, 0 ),
+ 'COUNTBLANK' => array( 347, 1, 0, 0 ),
+ 'ROMAN' => array( 354, -1, 1, 0 )
+ );
+ }
+
+ /**
+ * Convert a token to the proper ptg value.
+ *
+ * @access private
+ * @param mixed $token The token to convert.
+ * @return mixed the converted token on success. PEAR_Error if the token
+ * is not recognized
+ */
+ function _convert($token)
+ {
+ if (preg_match("/^\"[^\"]{0,255}\"$/", $token)) {
+ return $this->_convertString($token);
+
+ } elseif (is_numeric($token)) {
+ return $this->_convertNumber($token);
+
+ // match references like A1 or $A$1
+ } elseif (preg_match('/^\$?([A-Ia-i]?[A-Za-z])\$?(\d+)$/',$token)) {
+ return $this->_convertRef2d($token);
+
+ // match external references like Sheet1!A1 or Sheet1:Sheet2!A1
+ } elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z](\d+)$/u",$token)) {
+ return $this->_convertRef3d($token);
+
+ // match external references like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1
+ } elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z](\d+)$/u",$token)) {
+ return $this->_convertRef3d($token);
+
+ // match ranges like A1:B2
+ } elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)\:(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/",$token)) {
+ return $this->_convertRange2d($token);
+
+ // match ranges like A1..B2
+ } elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/",$token)) {
+ return $this->_convertRange2d($token);
+
+ // match external ranges like Sheet1!A1 or Sheet1:Sheet2!A1:B2
+ } elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?(\d+)\:([A-Ia-i]?[A-Za-z])?(\d+)$/u",$token)) {
+ return $this->_convertRange3d($token);
+
+ // match external ranges like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1:B2
+ } elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?(\d+)\:([A-Ia-i]?[A-Za-z])?(\d+)$/u",$token)) {
+ return $this->_convertRange3d($token);
+
+ // operators (including parentheses)
+ } elseif (isset($this->ptg[$token])) {
+ return pack("C", $this->ptg[$token]);
+
+ // commented so argument number can be processed correctly. See toReversePolish().
+ /*elseif (preg_match("/[A-Z0-9\xc0-\xdc\.]+/",$token))
+ {
+ return($this->_convertFunction($token,$this->_func_args));
+ }*/
+
+ // if it's an argument, ignore the token (the argument remains)
+ } elseif ($token == 'arg') {
+ return '';
+ }
+ // TODO: use real error codes
+ return $this->raiseError("Unknown token $token");
+ }
+
+ /**
+ * Convert a number token to ptgInt or ptgNum
+ *
+ * @access private
+ * @param mixed $num an integer or double for conversion to its ptg value
+ */
+ function _convertNumber($num)
+ {
+ // Integer in the range 0..2**16-1
+ if ((preg_match("/^\d+$/", $num)) and ($num <= 65535)) {
+ return pack("Cv", $this->ptg['ptgInt'], $num);
+ } else { // A float
+ if ($this->_byte_order) { // if it's Big Endian
+ $num = strrev($num);
+ }
+ return pack("Cd", $this->ptg['ptgNum'], $num);
+ }
+ }
+
+ /**
+ * Convert a string token to ptgStr
+ *
+ * @access private
+ * @param string $string A string for conversion to its ptg value.
+ * @return mixed the converted token on success. PEAR_Error if the string
+ * is longer than 255 characters.
+ */
+ function _convertString($string)
+ {
+ // chop away beggining and ending quotes
+ $string = substr($string, 1, strlen($string) - 2);
+ if (strlen($string) > 255) {
+ return $this->raiseError("String is too long");
+ }
+
+ if ($this->_BIFF_version == 0x0500) {
+ return pack("CC", $this->ptg['ptgStr'], strlen($string)).$string;
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $encoding = 0; // TODO: Unicode support
+ return pack("CCC", $this->ptg['ptgStr'], strlen($string), $encoding).$string;
+ }
+ }
+
+ /**
+ * Convert a function to a ptgFunc or ptgFuncVarV depending on the number of
+ * args that it takes.
+ *
+ * @access private
+ * @param string $token The name of the function for convertion to ptg value.
+ * @param integer $num_args The number of arguments the function receives.
+ * @return string The packed ptg for the function
+ */
+ function _convertFunction($token, $num_args)
+ {
+ $args = $this->_functions[$token][1];
+ $volatile = $this->_functions[$token][3];
+
+ // Fixed number of args eg. TIME($i,$j,$k).
+ if ($args >= 0) {
+ return pack("Cv", $this->ptg['ptgFuncV'], $this->_functions[$token][0]);
+ }
+ // Variable number of args eg. SUM($i,$j,$k, ..).
+ if ($args == -1) {
+ return pack("CCv", $this->ptg['ptgFuncVarV'], $num_args, $this->_functions[$token][0]);
+ }
+ }
+
+ /**
+ * Convert an Excel range such as A1:D4 to a ptgRefV.
+ *
+ * @access private
+ * @param string $range An Excel range in the A1:A2 or A1..A2 format.
+ */
+ function _convertRange2d($range)
+ {
+ $class = 2; // as far as I know, this is magick.
+
+ // Split the range into 2 cell refs
+ if (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\:([A-Ia-i]?[A-Za-z])(\d+)$/", $range)) {
+ list($cell1, $cell2) = split(':', $range);
+ } elseif (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\.\.([A-Ia-i]?[A-Za-z])(\d+)$/", $range)) {
+ list($cell1, $cell2) = split('\.\.', $range);
+
+ } else {
+ // TODO: use real error codes
+ return $this->raiseError("Unknown range separator", 0, PEAR_ERROR_DIE);
+ }
+
+ // Convert the cell references
+ $cell_array1 = $this->_cellToPackedRowcol($cell1);
+ if (PEAR::isError($cell_array1)) {
+ return $cell_array1;
+ }
+ list($row1, $col1) = $cell_array1;
+ $cell_array2 = $this->_cellToPackedRowcol($cell2);
+ if (PEAR::isError($cell_array2)) {
+ return $cell_array2;
+ }
+ list($row2, $col2) = $cell_array2;
+
+ // The ptg value depends on the class of the ptg.
+ if ($class == 0) {
+ $ptgArea = pack("C", $this->ptg['ptgArea']);
+ } elseif ($class == 1) {
+ $ptgArea = pack("C", $this->ptg['ptgAreaV']);
+ } elseif ($class == 2) {
+ $ptgArea = pack("C", $this->ptg['ptgAreaA']);
+ } else {
+ // TODO: use real error codes
+ return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE);
+ }
+ return $ptgArea . $row1 . $row2 . $col1. $col2;
+ }
+
+ /**
+ * Convert an Excel 3d range such as "Sheet1!A1:D4" or "Sheet1:Sheet2!A1:D4" to
+ * a ptgArea3d.
+ *
+ * @access private
+ * @param string $token An Excel range in the Sheet1!A1:A2 format.
+ * @return mixed The packed ptgArea3d token on success, PEAR_Error on failure.
+ */
+ function _convertRange3d($token)
+ {
+ $class = 2; // as far as I know, this is magick.
+
+ // Split the ref at the ! symbol
+ list($ext_ref, $range) = split('!', $token);
+
+ // Convert the external reference part (different for BIFF8)
+ if ($this->_BIFF_version == 0x0500) {
+ $ext_ref = $this->_packExtRef($ext_ref);
+ if (PEAR::isError($ext_ref)) {
+ return $ext_ref;
+ }
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $ext_ref = $this->_getRefIndex($ext_ref);
+ if (PEAR::isError($ext_ref)) {
+ return $ext_ref;
+ }
+ }
+
+ // Split the range into 2 cell refs
+ list($cell1, $cell2) = split(':', $range);
+
+ // Convert the cell references
+ if (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/", $cell1)) {
+ $cell_array1 = $this->_cellToPackedRowcol($cell1);
+ if (PEAR::isError($cell_array1)) {
+ return $cell_array1;
+ }
+ list($row1, $col1) = $cell_array1;
+ $cell_array2 = $this->_cellToPackedRowcol($cell2);
+ if (PEAR::isError($cell_array2)) {
+ return $cell_array2;
+ }
+ list($row2, $col2) = $cell_array2;
+ } else { // It's a rows range (like 26:27)
+ $cells_array = $this->_rangeToPackedRange($cell1.':'.$cell2);
+ if (PEAR::isError($cells_array)) {
+ return $cells_array;
+ }
+ list($row1, $col1, $row2, $col2) = $cells_array;
+ }
+
+ // The ptg value depends on the class of the ptg.
+ if ($class == 0) {
+ $ptgArea = pack("C", $this->ptg['ptgArea3d']);
+ } elseif ($class == 1) {
+ $ptgArea = pack("C", $this->ptg['ptgArea3dV']);
+ } elseif ($class == 2) {
+ $ptgArea = pack("C", $this->ptg['ptgArea3dA']);
+ } else {
+ return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE);
+ }
+
+ return $ptgArea . $ext_ref . $row1 . $row2 . $col1. $col2;
+ }
+
+ /**
+ * Convert an Excel reference such as A1, $B2, C$3 or $D$4 to a ptgRefV.
+ *
+ * @access private
+ * @param string $cell An Excel cell reference
+ * @return string The cell in packed() format with the corresponding ptg
+ */
+ function _convertRef2d($cell)
+ {
+ $class = 2; // as far as I know, this is magick.
+
+ // Convert the cell reference
+ $cell_array = $this->_cellToPackedRowcol($cell);
+ if (PEAR::isError($cell_array)) {
+ return $cell_array;
+ }
+ list($row, $col) = $cell_array;
+
+ // The ptg value depends on the class of the ptg.
+ if ($class == 0) {
+ $ptgRef = pack("C", $this->ptg['ptgRef']);
+ } elseif ($class == 1) {
+ $ptgRef = pack("C", $this->ptg['ptgRefV']);
+ } elseif ($class == 2) {
+ $ptgRef = pack("C", $this->ptg['ptgRefA']);
+ } else {
+ // TODO: use real error codes
+ return $this->raiseError("Unknown class $class");
+ }
+ return $ptgRef.$row.$col;
+ }
+
+ /**
+ * Convert an Excel 3d reference such as "Sheet1!A1" or "Sheet1:Sheet2!A1" to a
+ * ptgRef3d.
+ *
+ * @access private
+ * @param string $cell An Excel cell reference
+ * @return mixed The packed ptgRef3d token on success, PEAR_Error on failure.
+ */
+ function _convertRef3d($cell)
+ {
+ $class = 2; // as far as I know, this is magick.
+
+ // Split the ref at the ! symbol
+ list($ext_ref, $cell) = split('!', $cell);
+
+ // Convert the external reference part (different for BIFF8)
+ if ($this->_BIFF_version == 0x0500) {
+ $ext_ref = $this->_packExtRef($ext_ref);
+ if (PEAR::isError($ext_ref)) {
+ return $ext_ref;
+ }
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $ext_ref = $this->_getRefIndex($ext_ref);
+ if (PEAR::isError($ext_ref)) {
+ return $ext_ref;
+ }
+ }
+
+ // Convert the cell reference part
+ list($row, $col) = $this->_cellToPackedRowcol($cell);
+
+ // The ptg value depends on the class of the ptg.
+ if ($class == 0) {
+ $ptgRef = pack("C", $this->ptg['ptgRef3d']);
+ } elseif ($class == 1) {
+ $ptgRef = pack("C", $this->ptg['ptgRef3dV']);
+ } elseif ($class == 2) {
+ $ptgRef = pack("C", $this->ptg['ptgRef3dA']);
+ } else {
+ return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE);
+ }
+
+ return $ptgRef . $ext_ref. $row . $col;
+ }
+
+ /**
+ * Convert the sheet name part of an external reference, for example "Sheet1" or
+ * "Sheet1:Sheet2", to a packed structure.
+ *
+ * @access private
+ * @param string $ext_ref The name of the external reference
+ * @return string The reference index in packed() format
+ */
+ function _packExtRef($ext_ref)
+ {
+ $ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading ' if any.
+ $ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any.
+
+ // Check if there is a sheet range eg., Sheet1:Sheet2.
+ if (preg_match("/:/", $ext_ref)) {
+ list($sheet_name1, $sheet_name2) = split(':', $ext_ref);
+
+ $sheet1 = $this->_getSheetIndex($sheet_name1);
+ if ($sheet1 == -1) {
+ return $this->raiseError("Unknown sheet name $sheet_name1 in formula");
+ }
+ $sheet2 = $this->_getSheetIndex($sheet_name2);
+ if ($sheet2 == -1) {
+ return $this->raiseError("Unknown sheet name $sheet_name2 in formula");
+ }
+
+ // Reverse max and min sheet numbers if necessary
+ if ($sheet1 > $sheet2) {
+ list($sheet1, $sheet2) = array($sheet2, $sheet1);
+ }
+ } else { // Single sheet name only.
+ $sheet1 = $this->_getSheetIndex($ext_ref);
+ if ($sheet1 == -1) {
+ return $this->raiseError("Unknown sheet name $ext_ref in formula");
+ }
+ $sheet2 = $sheet1;
+ }
+
+ // References are stored relative to 0xFFFF.
+ $offset = -1 - $sheet1;
+
+ return pack('vdvv', $offset, 0x00, $sheet1, $sheet2);
+ }
+
+ /**
+ * Look up the REF index that corresponds to an external sheet name
+ * (or range). If it doesn't exist yet add it to the workbook's references
+ * array. It assumes all sheet names given must exist.
+ *
+ * @access private
+ * @param string $ext_ref The name of the external reference
+ * @return mixed The reference index in packed() format on success,
+ * PEAR_Error on failure
+ */
+ function _getRefIndex($ext_ref)
+ {
+ $ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading ' if any.
+ $ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any.
+
+ // Check if there is a sheet range eg., Sheet1:Sheet2.
+ if (preg_match("/:/", $ext_ref)) {
+ list($sheet_name1, $sheet_name2) = split(':', $ext_ref);
+
+ $sheet1 = $this->_getSheetIndex($sheet_name1);
+ if ($sheet1 == -1) {
+ return $this->raiseError("Unknown sheet name $sheet_name1 in formula");
+ }
+ $sheet2 = $this->_getSheetIndex($sheet_name2);
+ if ($sheet2 == -1) {
+ return $this->raiseError("Unknown sheet name $sheet_name2 in formula");
+ }
+
+ // Reverse max and min sheet numbers if necessary
+ if ($sheet1 > $sheet2) {
+ list($sheet1, $sheet2) = array($sheet2, $sheet1);
+ }
+ } else { // Single sheet name only.
+ $sheet1 = $this->_getSheetIndex($ext_ref);
+ if ($sheet1 == -1) {
+ return $this->raiseError("Unknown sheet name $ext_ref in formula");
+ }
+ $sheet2 = $sheet1;
+ }
+
+ // assume all references belong to this document
+ $supbook_index = 0x00;
+ $ref = pack('vvv', $supbook_index, $sheet1, $sheet2);
+ $total_references = count($this->_references);
+ $index = -1;
+ for ($i = 0; $i < $total_references; $i++) {
+ if ($ref == $this->_references[$i]) {
+ $index = $i;
+ break;
+ }
+ }
+ // if REF was not found add it to references array
+ if ($index == -1) {
+ $this->_references[$total_references] = $ref;
+ $index = $total_references;
+ }
+
+ return pack('v', $index);
+ }
+
+ /**
+ * Look up the index that corresponds to an external sheet name. The hash of
+ * sheet names is updated by the addworksheet() method of the
+ * Spreadsheet_Excel_Writer_Workbook class.
+ *
+ * @access private
+ * @return integer The sheet index, -1 if the sheet was not found
+ */
+ function _getSheetIndex($sheet_name)
+ {
+ if (!isset($this->_ext_sheets[$sheet_name])) {
+ return -1;
+ } else {
+ return $this->_ext_sheets[$sheet_name];
+ }
+ }
+
+ /**
+ * This method is used to update the array of sheet names. It is
+ * called by the addWorksheet() method of the
+ * Spreadsheet_Excel_Writer_Workbook class.
+ *
+ * @access public
+ * @see Spreadsheet_Excel_Writer_Workbook::addWorksheet()
+ * @param string $name The name of the worksheet being added
+ * @param integer $index The index of the worksheet being added
+ */
+ function setExtSheet($name, $index)
+ {
+ $this->_ext_sheets[$name] = $index;
+ }
+
+ /**
+ * pack() row and column into the required 3 or 4 byte format.
+ *
+ * @access private
+ * @param string $cell The Excel cell reference to be packed
+ * @return array Array containing the row and column in packed() format
+ */
+ function _cellToPackedRowcol($cell)
+ {
+ $cell = strtoupper($cell);
+ list($row, $col, $row_rel, $col_rel) = $this->_cellToRowcol($cell);
+ if ($col >= 256) {
+ return $this->raiseError("Column in: $cell greater than 255");
+ }
+ // FIXME: change for BIFF8
+ if ($row >= 16384) {
+ return $this->raiseError("Row in: $cell greater than 16384 ");
+ }
+
+ // Set the high bits to indicate if row or col are relative.
+ if ($this->_BIFF_version == 0x0500) {
+ $row |= $col_rel << 14;
+ $row |= $row_rel << 15;
+ $col = pack('C', $col);
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $col |= $col_rel << 14;
+ $col |= $row_rel << 15;
+ $col = pack('v', $col);
+ }
+ $row = pack('v', $row);
+
+ return array($row, $col);
+ }
+
+ /**
+ * pack() row range into the required 3 or 4 byte format.
+ * Just using maximum col/rows, which is probably not the correct solution
+ *
+ * @access private
+ * @param string $range The Excel range to be packed
+ * @return array Array containing (row1,col1,row2,col2) in packed() format
+ */
+ function _rangeToPackedRange($range)
+ {
+ preg_match('/(\$)?(\d+)\:(\$)?(\d+)/', $range, $match);
+ // return absolute rows if there is a $ in the ref
+ $row1_rel = empty($match[1]) ? 1 : 0;
+ $row1 = $match[2];
+ $row2_rel = empty($match[3]) ? 1 : 0;
+ $row2 = $match[4];
+ // Convert 1-index to zero-index
+ $row1--;
+ $row2--;
+ // Trick poor inocent Excel
+ $col1 = 0;
+ $col2 = 16383; // FIXME: maximum possible value for Excel 5 (change this!!!)
+
+ // FIXME: this changes for BIFF8
+ if (($row1 >= 16384) or ($row2 >= 16384)) {
+ return $this->raiseError("Row in: $range greater than 16384 ");
+ }
+
+ // Set the high bits to indicate if rows are relative.
+ if ($this->_BIFF_version == 0x0500) {
+ $row1 |= $row1_rel << 14; // FIXME: probably a bug
+ $row2 |= $row2_rel << 15;
+ $col1 = pack('C', $col1);
+ $col2 = pack('C', $col2);
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $col1 |= $row1_rel << 15;
+ $col2 |= $row2_rel << 15;
+ $col1 = pack('v', $col1);
+ $col2 = pack('v', $col2);
+ }
+ $row1 = pack('v', $row1);
+ $row2 = pack('v', $row2);
+
+ return array($row1, $col1, $row2, $col2);
+ }
+
+ /**
+ * Convert an Excel cell reference such as A1 or $B2 or C$3 or $D$4 to a zero
+ * indexed row and column number. Also returns two (0,1) values to indicate
+ * whether the row or column are relative references.
+ *
+ * @access private
+ * @param string $cell The Excel cell reference in A1 format.
+ * @return array
+ */
+ function _cellToRowcol($cell)
+ {
+ preg_match('/(\$)?([A-I]?[A-Z])(\$)?(\d+)/',$cell,$match);
+ // return absolute column if there is a $ in the ref
+ $col_rel = empty($match[1]) ? 1 : 0;
+ $col_ref = $match[2];
+ $row_rel = empty($match[3]) ? 1 : 0;
+ $row = $match[4];
+
+ // Convert base26 column string to a number.
+ $expn = strlen($col_ref) - 1;
+ $col = 0;
+ $col_ref_length = strlen($col_ref);
+ for ($i = 0; $i < $col_ref_length; $i++) {
+ $col += (ord($col_ref{$i}) - ord('A') + 1) * pow(26, $expn);
+ $expn--;
+ }
+
+ // Convert 1-index to zero-index
+ $row--;
+ $col--;
+
+ return array($row, $col, $row_rel, $col_rel);
+ }
+
+ /**
+ * Advance to the next valid token.
+ *
+ * @access private
+ */
+ function _advance()
+ {
+ $i = $this->_current_char;
+ $formula_length = strlen($this->_formula);
+ // eat up white spaces
+ if ($i < $formula_length) {
+ while ($this->_formula{$i} == " ") {
+ $i++;
+ }
+
+ if ($i < ($formula_length - 1)) {
+ $this->_lookahead = $this->_formula{$i+1};
+ }
+ $token = '';
+ }
+
+ while ($i < $formula_length) {
+ $token .= $this->_formula{$i};
+ if ($i < ($formula_length - 1)) {
+ $this->_lookahead = $this->_formula{$i+1};
+ } else {
+ $this->_lookahead = '';
+ }
+
+ if ($this->_match($token) != '') {
+ //if ($i < strlen($this->_formula) - 1) {
+ // $this->_lookahead = $this->_formula{$i+1};
+ //}
+ $this->_current_char = $i + 1;
+ $this->_current_token = $token;
+ return 1;
+ }
+
+ if ($i < ($formula_length - 2)) {
+ $this->_lookahead = $this->_formula{$i+2};
+ } else { // if we run out of characters _lookahead becomes empty
+ $this->_lookahead = '';
+ }
+ $i++;
+ }
+ //die("Lexical error ".$this->_current_char);
+ }
+
+ /**
+ * Checks if it's a valid token.
+ *
+ * @access private
+ * @param mixed $token The token to check.
+ * @return mixed The checked token or false on failure
+ */
+ function _match($token)
+ {
+ switch($token) {
+ case SPREADSHEET_EXCEL_WRITER_ADD:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_SUB:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_MUL:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_DIV:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_OPEN:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_CLOSE:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_COMA:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_SEMICOLON:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_GT:
+ if ($this->_lookahead == '=') { // it's a GE token
+ break;
+ }
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_LT:
+ // it's a LE or a NE token
+ if (($this->_lookahead == '=') or ($this->_lookahead == '>')) {
+ break;
+ }
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_GE:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_LE:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_EQ:
+ return $token;
+ break;
+ case SPREADSHEET_EXCEL_WRITER_NE:
+ return $token;
+ break;
+ default:
+ // if it's a reference
+ if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$token) and
+ !ereg("[0-9]",$this->_lookahead) and
+ ($this->_lookahead != ':') and ($this->_lookahead != '.') and
+ ($this->_lookahead != '!'))
+ {
+ return $token;
+ }
+ // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1)
+ elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z][0-9]+$/u",$token) and
+ !ereg("[0-9]",$this->_lookahead) and
+ ($this->_lookahead != ':') and ($this->_lookahead != '.'))
+ {
+ return $token;
+ }
+ // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1)
+ elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z][0-9]+$/u",$token) and
+ !ereg("[0-9]",$this->_lookahead) and
+ ($this->_lookahead != ':') and ($this->_lookahead != '.'))
+ {
+ return $token;
+ }
+ // if it's a range (A1:A2)
+ elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and
+ !ereg("[0-9]",$this->_lookahead))
+ {
+ return $token;
+ }
+ // if it's a range (A1..A2)
+ elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and
+ !ereg("[0-9]",$this->_lookahead))
+ {
+ return $token;
+ }
+ // If it's an external range like Sheet1!A1 or Sheet1:Sheet2!A1:B2
+ elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$token) and
+ !ereg("[0-9]",$this->_lookahead))
+ {
+ return $token;
+ }
+ // If it's an external range like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1:B2
+ elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$token) and
+ !ereg("[0-9]",$this->_lookahead))
+ {
+ return $token;
+ }
+ // If it's a number (check that it's not a sheet name or range)
+ elseif (is_numeric($token) and
+ (!is_numeric($token.$this->_lookahead) or ($this->_lookahead == '')) and
+ ($this->_lookahead != '!') and ($this->_lookahead != ':'))
+ {
+ return $token;
+ }
+ // If it's a string (of maximum 255 characters)
+ elseif (ereg("^\"[^\"]{0,255}\"$",$token))
+ {
+ return $token;
+ }
+ // if it's a function call
+ elseif (eregi("^[A-Z0-9\xc0-\xdc\.]+$",$token) and ($this->_lookahead == "("))
+ {
+ return $token;
+ }
+ return '';
+ }
+ }
+
+ /**
+ * The parsing method. It parses a formula.
+ *
+ * @access public
+ * @param string $formula The formula to parse, without the initial equal
+ * sign (=).
+ * @return mixed true on success, PEAR_Error on failure
+ */
+ function parse($formula)
+ {
+ $this->_current_char = 0;
+ $this->_formula = $formula;
+ $this->_lookahead = $formula{1};
+ $this->_advance();
+ $this->_parse_tree = $this->_condition();
+ if (PEAR::isError($this->_parse_tree)) {
+ return $this->_parse_tree;
+ }
+ return true;
+ }
+
+ /**
+ * It parses a condition. It assumes the following rule:
+ * Cond -> Expr [(">" | "<") Expr]
+ *
+ * @access private
+ * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure
+ */
+ function _condition()
+ {
+ $result = $this->_expression();
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LT) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgLT', $result, $result2);
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GT) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgGT', $result, $result2);
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LE) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgLE', $result, $result2);
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GE) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgGE', $result, $result2);
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_EQ) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgEQ', $result, $result2);
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_NE) {
+ $this->_advance();
+ $result2 = $this->_expression();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgNE', $result, $result2);
+ }
+ return $result;
+ }
+
+ /**
+ * It parses a expression. It assumes the following rule:
+ * Expr -> Term [("+" | "-") Term]
+ * -> "string"
+ * -> "-" Term
+ *
+ * @access private
+ * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure
+ */
+ function _expression()
+ {
+ // If it's a string return a string node
+ if (ereg("^\"[^\"]{0,255}\"$", $this->_current_token)) {
+ $result = $this->_createTree($this->_current_token, '', '');
+ $this->_advance();
+ return $result;
+ } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_SUB) {
+ // catch "-" Term
+ $this->_advance();
+ $result2 = $this->_expression();
+ $result = $this->_createTree('ptgUminus', $result2, '');
+ return $result;
+ }
+ $result = $this->_term();
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) or
+ ($this->_current_token == SPREADSHEET_EXCEL_WRITER_SUB)) {
+ /**/
+ if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) {
+ $this->_advance();
+ $result2 = $this->_term();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgAdd', $result, $result2);
+ } else {
+ $this->_advance();
+ $result2 = $this->_term();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgSub', $result, $result2);
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * This function just introduces a ptgParen element in the tree, so that Excel
+ * doesn't get confused when working with a parenthesized formula afterwards.
+ *
+ * @access private
+ * @see _fact()
+ * @return array The parsed ptg'd tree
+ */
+ function _parenthesizedExpression()
+ {
+ $result = $this->_createTree('ptgParen', $this->_expression(), '');
+ return $result;
+ }
+
+ /**
+ * It parses a term. It assumes the following rule:
+ * Term -> Fact [("*" | "/") Fact]
+ *
+ * @access private
+ * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure
+ */
+ function _term()
+ {
+ $result = $this->_fact();
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) or
+ ($this->_current_token == SPREADSHEET_EXCEL_WRITER_DIV)) {
+ /**/
+ if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) {
+ $this->_advance();
+ $result2 = $this->_fact();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgMul', $result, $result2);
+ } else {
+ $this->_advance();
+ $result2 = $this->_fact();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('ptgDiv', $result, $result2);
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * It parses a factor. It assumes the following rule:
+ * Fact -> ( Expr )
+ * | CellRef
+ * | CellRange
+ * | Number
+ * | Function
+ *
+ * @access private
+ * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure
+ */
+ function _fact()
+ {
+ if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_OPEN) {
+ $this->_advance(); // eat the "("
+ $result = $this->_parenthesizedExpression();
+ if ($this->_current_token != SPREADSHEET_EXCEL_WRITER_CLOSE) {
+ return $this->raiseError("')' token expected.");
+ }
+ $this->_advance(); // eat the ")"
+ return $result;
+ }
+ // if it's a reference
+ if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$this->_current_token))
+ {
+ $result = $this->_createTree($this->_current_token, '', '');
+ $this->_advance();
+ return $result;
+ }
+ // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1)
+ elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z][0-9]+$/u",$this->_current_token))
+ {
+ $result = $this->_createTree($this->_current_token, '', '');
+ $this->_advance();
+ return $result;
+ }
+ // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1)
+ elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z][0-9]+$/u",$this->_current_token))
+ {
+ $result = $this->_createTree($this->_current_token, '', '');
+ $this->_advance();
+ return $result;
+ }
+ // if it's a range
+ elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$this->_current_token) or
+ preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$this->_current_token))
+ {
+ $result = $this->_current_token;
+ $this->_advance();
+ return $result;
+ }
+ // If it's an external range (Sheet1!A1 or Sheet1!A1:B2)
+ elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$this->_current_token))
+ {
+ $result = $this->_current_token;
+ $this->_advance();
+ return $result;
+ }
+ // If it's an external range ('Sheet1'!A1 or 'Sheet1'!A1:B2)
+ elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$this->_current_token))
+ {
+ $result = $this->_current_token;
+ $this->_advance();
+ return $result;
+ }
+ elseif (is_numeric($this->_current_token))
+ {
+ $result = $this->_createTree($this->_current_token, '', '');
+ $this->_advance();
+ return $result;
+ }
+ // if it's a function call
+ elseif (eregi("^[A-Z0-9\xc0-\xdc\.]+$",$this->_current_token))
+ {
+ $result = $this->_func();
+ return $result;
+ }
+ return $this->raiseError("Syntax error: ".$this->_current_token.
+ ", lookahead: ".$this->_lookahead.
+ ", current char: ".$this->_current_char);
+ }
+
+ /**
+ * It parses a function call. It assumes the following rule:
+ * Func -> ( Expr [,Expr]* )
+ *
+ * @access private
+ * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure
+ */
+ function _func()
+ {
+ $num_args = 0; // number of arguments received
+ $function = strtoupper($this->_current_token);
+ $result = ''; // initialize result
+ $this->_advance();
+ $this->_advance(); // eat the "("
+ while ($this->_current_token != ')') {
+ /**/
+ if ($num_args > 0) {
+ if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_COMA or
+ $this->_current_token == SPREADSHEET_EXCEL_WRITER_SEMICOLON)
+ {
+ $this->_advance(); // eat the "," or ";"
+ } else {
+ return $this->raiseError("Syntax error: comma expected in ".
+ "function $function, arg #{$num_args}");
+ }
+ $result2 = $this->_condition();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('arg', $result, $result2);
+ } else { // first argument
+ $result2 = $this->_condition();
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $this->_createTree('arg', '', $result2);
+ }
+ $num_args++;
+ }
+ if (!isset($this->_functions[$function])) {
+ return $this->raiseError("Function $function() doesn't exist");
+ }
+ $args = $this->_functions[$function][1];
+ // If fixed number of args eg. TIME($i,$j,$k). Check that the number of args is valid.
+ if (($args >= 0) and ($args != $num_args)) {
+ return $this->raiseError("Incorrect number of arguments in function $function() ");
+ }
+
+ $result = $this->_createTree($function, $result, $num_args);
+ $this->_advance(); // eat the ")"
+ return $result;
+ }
+
+ /**
+ * Creates a tree. In fact an array which may have one or two arrays (sub-trees)
+ * as elements.
+ *
+ * @access private
+ * @param mixed $value The value of this node.
+ * @param mixed $left The left array (sub-tree) or a final node.
+ * @param mixed $right The right array (sub-tree) or a final node.
+ * @return array A tree
+ */
+ function _createTree($value, $left, $right)
+ {
+ return array('value' => $value, 'left' => $left, 'right' => $right);
+ }
+
+ /**
+ * Builds a string containing the tree in reverse polish notation (What you
+ * would use in a HP calculator stack).
+ * The following tree:
+ *
+ * +
+ * / \
+ * 2 3
+ *
+ * produces: "23+"
+ *
+ * The following tree:
+ *
+ * +
+ * / \
+ * 3 *
+ * / \
+ * 6 A1
+ *
+ * produces: "36A1*+"
+ *
+ * In fact all operands, functions, references, etc... are written as ptg's
+ *
+ * @access public
+ * @param array $tree The optional tree to convert.
+ * @return string The tree in reverse polish notation
+ */
+ function toReversePolish($tree = array())
+ {
+ $polish = ""; // the string we are going to return
+ if (empty($tree)) { // If it's the first call use _parse_tree
+ $tree = $this->_parse_tree;
+ }
+ if (is_array($tree['left'])) {
+ $converted_tree = $this->toReversePolish($tree['left']);
+ if (PEAR::isError($converted_tree)) {
+ return $converted_tree;
+ }
+ $polish .= $converted_tree;
+ } elseif ($tree['left'] != '') { // It's a final node
+ $converted_tree = $this->_convert($tree['left']);
+ if (PEAR::isError($converted_tree)) {
+ return $converted_tree;
+ }
+ $polish .= $converted_tree;
+ }
+ if (is_array($tree['right'])) {
+ $converted_tree = $this->toReversePolish($tree['right']);
+ if (PEAR::isError($converted_tree)) {
+ return $converted_tree;
+ }
+ $polish .= $converted_tree;
+ } elseif ($tree['right'] != '') { // It's a final node
+ $converted_tree = $this->_convert($tree['right']);
+ if (PEAR::isError($converted_tree)) {
+ return $converted_tree;
+ }
+ $polish .= $converted_tree;
+ }
+ // if it's a function convert it here (so we can set it's arguments)
+ if (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/",$tree['value']) and
+ !preg_match('/^([A-Ia-i]?[A-Za-z])(\d+)$/',$tree['value']) and
+ !preg_match("/^[A-Ia-i]?[A-Za-z](\d+)\.\.[A-Ia-i]?[A-Za-z](\d+)$/",$tree['value']) and
+ !is_numeric($tree['value']) and
+ !isset($this->ptg[$tree['value']]))
+ {
+ // left subtree for a function is always an array.
+ if ($tree['left'] != '') {
+ $left_tree = $this->toReversePolish($tree['left']);
+ } else {
+ $left_tree = '';
+ }
+ if (PEAR::isError($left_tree)) {
+ return $left_tree;
+ }
+ // add it's left subtree and return.
+ return $left_tree.$this->_convertFunction($tree['value'], $tree['right']);
+ } else {
+ $converted_tree = $this->_convert($tree['value']);
+ if (PEAR::isError($converted_tree)) {
+ return $converted_tree;
+ }
+ }
+ $polish .= $converted_tree;
+ return $polish;
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/ExcelWriter/Validator.php b/vendor/library/Excel/phpxls/ExcelWriter/Validator.php
new file mode 100644
index 0000000..0f091c6
--- /dev/null
+++ b/vendor/library/Excel/phpxls/ExcelWriter/Validator.php
@@ -0,0 +1,230 @@
+
+*
+* License Information:
+*
+* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
+* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+//require_once('PEAR.php');
+
+// Possible operator types
+
+/*
+FIXME: change prefixes
+*/
+define("OP_BETWEEN", 0x00);
+define("OP_NOTBETWEEN", 0x01);
+define("OP_EQUAL", 0x02);
+define("OP_NOTEQUAL", 0x03);
+define("OP_GT", 0x04);
+define("OP_LT", 0x05);
+define("OP_GTE", 0x06);
+define("OP_LTE", 0x07);
+
+/**
+* Baseclass for generating Excel DV records (validations)
+*
+* @author Herman Kuiper
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+class Spreadsheet_Excel_Writer_Validator
+{
+ var $_type;
+ var $_style;
+ var $_fixedList;
+ var $_blank;
+ var $_incell;
+ var $_showprompt;
+ var $_showerror;
+ var $_title_prompt;
+ var $_descr_prompt;
+ var $_title_error;
+ var $_descr_error;
+ var $_operator;
+ var $_formula1;
+ var $_formula2;
+ /**
+ * The parser from the workbook. Used to parse validation formulas also
+ * @var Spreadsheet_Excel_Writer_Parser
+ */
+ var $_parser;
+
+ function Spreadsheet_Excel_Writer_Validator(&$parser)
+ {
+ $this->_parser = $parser;
+ $this->_type = 0x01; // FIXME: add method for setting datatype
+ $this->_style = 0x00;
+ $this->_fixedList = false;
+ $this->_blank = false;
+ $this->_incell = false;
+ $this->_showprompt = false;
+ $this->_showerror = true;
+ $this->_title_prompt = "\x00";
+ $this->_descr_prompt = "\x00";
+ $this->_title_error = "\x00";
+ $this->_descr_error = "\x00";
+ $this->_operator = 0x00; // default is equal
+ $this->_formula1 = '';
+ $this->_formula2 = '';
+ }
+
+ function setPrompt($promptTitle = "\x00", $promptDescription = "\x00", $showPrompt = true)
+ {
+ $this->_showprompt = $showPrompt;
+ $this->_title_prompt = $promptTitle;
+ $this->_descr_prompt = $promptDescription;
+ }
+
+ function setError($errorTitle = "\x00", $errorDescription = "\x00", $showError = true)
+ {
+ $this->_showerror = $showError;
+ $this->_title_error = $errorTitle;
+ $this->_descr_error = $errorDescription;
+ }
+
+ function allowBlank()
+ {
+ $this->_blank = true;
+ }
+
+ function onInvalidStop()
+ {
+ $this->_style = 0x00;
+ }
+
+ function onInvalidWarn()
+ {
+ $this->_style = 0x01;
+ }
+
+ function onInvalidInfo()
+ {
+ $this->_style = 0x02;
+ }
+
+ function setFormula1($formula)
+ {
+ // Parse the formula using the parser in Parser.php
+ $error = $this->_parser->parse($formula);
+ if (PEAR::isError($error)) {
+ return $this->_formula1;
+ }
+
+ $this->_formula1 = $this->_parser->toReversePolish();
+ if (PEAR::isError($this->_formula1)) {
+ return $this->_formula1;
+ }
+ return true;
+ }
+
+ function setFormula2($formula)
+ {
+ // Parse the formula using the parser in Parser.php
+ $error = $this->_parser->parse($formula);
+ if (PEAR::isError($error)) {
+ return $this->_formula2;
+ }
+
+ $this->_formula2 = $this->_parser->toReversePolish();
+ if (PEAR::isError($this->_formula2)) {
+ return $this->_formula2;
+ }
+ return true;
+ }
+
+ function _getOptions()
+ {
+ $options = $this->_type;
+ $options |= $this->_style << 3;
+ if ($this->_fixedList) {
+ $options |= 0x80;
+ }
+ if ($this->_blank) {
+ $options |= 0x100;
+ }
+ if (!$this->_incell) {
+ $options |= 0x200;
+ }
+ if ($this->_showprompt) {
+ $options |= 0x40000;
+ }
+ if ($this->_showerror) {
+ $options |= 0x80000;
+ }
+ $options |= $this->_operator << 20;
+
+ return $options;
+ }
+
+ function _getData()
+ {
+ $title_prompt_len = strlen($this->_title_prompt);
+ $descr_prompt_len = strlen($this->_descr_prompt);
+ $title_error_len = strlen($this->_title_error);
+ $descr_error_len = strlen($this->_descr_error);
+
+ $formula1_size = strlen($this->_formula1);
+ $formula2_size = strlen($this->_formula2);
+
+ $data = pack("V", $this->_getOptions());
+ $data .= pack("vC", $title_prompt_len, 0x00) . $this->_title_prompt;
+ $data .= pack("vC", $title_error_len, 0x00) . $this->_title_error;
+ $data .= pack("vC", $descr_prompt_len, 0x00) . $this->_descr_prompt;
+ $data .= pack("vC", $descr_error_len, 0x00) . $this->_descr_error;
+
+ $data .= pack("vv", $formula1_size, 0x0000) . $this->_formula1;
+ $data .= pack("vv", $formula2_size, 0x0000) . $this->_formula2;
+
+ return $data;
+ }
+}
+
+/*class Spreadsheet_Excel_Writer_Validation_List extends Spreadsheet_Excel_Writer_Validation
+{
+ function Spreadsheet_Excel_Writer_Validation_list()
+ {
+ parent::Spreadsheet_Excel_Writer_Validation();
+ $this->_type = 0x03;
+ }
+
+ function setList($source, $incell = true)
+ {
+ $this->_incell = $incell;
+ $this->_fixedList = true;
+
+ $source = implode("\x00", $source);
+ $this->_formula1 = pack("CCC", 0x17, strlen($source), 0x0c) . $source;
+ }
+
+ function setRow($row, $col1, $col2, $incell = true)
+ {
+ $this->_incell = $incell;
+ //$this->_formula1 = ...;
+ }
+
+ function setCol($col, $row1, $row2, $incell = true)
+ {
+ $this->_incell = $incell;
+ //$this->_formula1 = ...;
+ }
+}*/
+
+?>
diff --git a/vendor/library/Excel/phpxls/ExcelWriter/Workbook.php b/vendor/library/Excel/phpxls/ExcelWriter/Workbook.php
new file mode 100644
index 0000000..a5cd289
--- /dev/null
+++ b/vendor/library/Excel/phpxls/ExcelWriter/Workbook.php
@@ -0,0 +1,1533 @@
+
+*
+* The majority of this is _NOT_ my code. I simply ported it from the
+* PERL Spreadsheet::WriteExcel module.
+*
+* The author of the Spreadsheet::WriteExcel module is John McNamara
+*
+*
+* I _DO_ maintain this code, and John McNamara has nothing to do with the
+* porting of this code to PHP. Any questions directly related to this
+* class library should be directed to me.
+*
+* License Information:
+*
+* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
+* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+require_once 'ExcelWriter/Format.php';
+require_once 'ExcelWriter/BIFFwriter.php';
+require_once 'ExcelWriter/Worksheet.php';
+require_once 'ExcelWriter/Parser.php';
+require_once 'OLE/PPS/Root.php';
+require_once 'OLE/PPS/File.php';
+
+/**
+* Class for generating Excel Spreadsheets
+*
+* @author Xavier Noguer
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+
+class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwriter
+{
+ /**
+ * Filename for the Workbook
+ * @var string
+ */
+ var $_filename;
+
+ /**
+ * Formula parser
+ * @var object Parser
+ */
+ var $_parser;
+
+ /**
+ * Flag for 1904 date system (0 => base date is 1900, 1 => base date is 1904)
+ * @var integer
+ */
+ var $_1904;
+
+ /**
+ * The active worksheet of the workbook (0 indexed)
+ * @var integer
+ */
+ var $_activesheet;
+
+ /**
+ * 1st displayed worksheet in the workbook (0 indexed)
+ * @var integer
+ */
+ var $_firstsheet;
+
+ /**
+ * Number of workbook tabs selected
+ * @var integer
+ */
+ var $_selected;
+
+ /**
+ * Index for creating adding new formats to the workbook
+ * @var integer
+ */
+ var $_xf_index;
+
+ /**
+ * Flag for preventing close from being called twice.
+ * @var integer
+ * @see close()
+ */
+ var $_fileclosed;
+
+ /**
+ * The BIFF file size for the workbook.
+ * @var integer
+ * @see _calcSheetOffsets()
+ */
+ var $_biffsize;
+
+ /**
+ * The default sheetname for all sheets created.
+ * @var string
+ */
+ var $_sheetname;
+
+ /**
+ * The default XF format.
+ * @var object Format
+ */
+ var $_tmp_format;
+
+ /**
+ * Array containing references to all of this workbook's worksheets
+ * @var array
+ */
+ var $_worksheets;
+
+ /**
+ * Array of sheetnames for creating the EXTERNSHEET records
+ * @var array
+ */
+ var $_sheetnames;
+
+ /**
+ * Array containing references to all of this workbook's formats
+ * @var array
+ */
+ var $_formats;
+
+ /**
+ * Array containing the colour palette
+ * @var array
+ */
+ var $_palette;
+
+ /**
+ * The default format for URLs.
+ * @var object Format
+ */
+ var $_url_format;
+
+ /**
+ * The codepage indicates the text encoding used for strings
+ * @var integer
+ */
+ var $_codepage;
+
+ /**
+ * The country code used for localization
+ * @var integer
+ */
+ var $_country_code;
+
+ /**
+ * The temporary dir for storing the OLE file
+ * @var string
+ */
+ var $_tmp_dir;
+
+ /**
+ * number of bytes for sizeinfo of strings
+ * @var integer
+ */
+ var $_string_sizeinfo_size;
+
+ /**
+ * Class constructor
+ *
+ * @param string filename for storing the workbook. "-" for writing to stdout.
+ * @access public
+ */
+
+ function __construct(){}
+
+ function Spreadsheet_Excel_Writer_Workbook($filename)
+ {
+ // It needs to call its parent's constructor explicitly
+ $this->Spreadsheet_Excel_Writer_BIFFwriter();
+
+ $this->_filename = $filename;
+ //$this->_parser =& new Spreadsheet_Excel_Writer_Parser($this->_byte_order, $this->_BIFF_version);
+ $this->_parser = new Spreadsheet_Excel_Writer_Parser($this->_byte_order, $this->_BIFF_version);
+ $this->_1904 = 0;
+ $this->_activesheet = 0;
+ $this->_firstsheet = 0;
+ $this->_selected = 0;
+ $this->_xf_index = 16; // 15 style XF's and 1 cell XF.
+ $this->_fileclosed = 0;
+ $this->_biffsize = 0;
+ $this->_sheetname = 'Sheet';
+ //$this->_tmp_format =& new Spreadsheet_Excel_Writer_Format($this->_BIFF_version);
+ $this->_tmp_format = new Spreadsheet_Excel_Writer_Format($this->_BIFF_version);
+ $this->_worksheets = array();
+ $this->_sheetnames = array();
+ $this->_formats = array();
+ $this->_palette = array();
+ $this->_codepage = 0x04E4; // FIXME: should change for BIFF8
+ $this->_country_code = -1;
+ $this->_string_sizeinfo = 3;
+
+ // Add the default format for hyperlinks
+ $this->_url_format =& $this->addFormat(array('color' => 'blue', 'underline' => 1));
+ $this->_str_total = 0;
+ $this->_str_unique = 0;
+ $this->_str_table = array();
+ $this->_setPaletteXl97();
+ $this->_tmp_dir = '';
+ }
+
+ /**
+ * Calls finalization methods.
+ * This method should always be the last one to be called on every workbook
+ *
+ * @access public
+ * @return mixed true on success. PEAR_Error on failure
+ */
+ function close()
+ {
+ if ($this->_fileclosed) { // Prevent close() from being called twice.
+ return true;
+ }
+ $res = $this->_storeWorkbook();
+ if ($this->isError($res)) {
+ return $this->raiseError($res->getMessage());
+ }
+ $this->_fileclosed = 1;
+ return true;
+ }
+
+ /**
+ * An accessor for the _worksheets[] array
+ * Returns an array of the worksheet objects in a workbook
+ * It actually calls to worksheets()
+ *
+ * @access public
+ * @see worksheets()
+ * @return array
+ */
+ function sheets()
+ {
+ return $this->worksheets();
+ }
+
+ /**
+ * An accessor for the _worksheets[] array.
+ * Returns an array of the worksheet objects in a workbook
+ *
+ * @access public
+ * @return array
+ */
+ function worksheets()
+ {
+ return $this->_worksheets;
+ }
+
+ /**
+ * Sets the BIFF version.
+ * This method exists just to access experimental functionality
+ * from BIFF8. It will be deprecated !
+ * Only possible value is 8 (Excel 97/2000).
+ * For any other value it fails silently.
+ *
+ * @access public
+ * @param integer $version The BIFF version
+ */
+ function setVersion($version)
+ {
+ if ($version == 8) { // only accept version 8
+ $version = 0x0600;
+ $this->_BIFF_version = $version;
+ // change BIFFwriter limit for CONTINUE records
+ $this->_limit = 8228;
+ $this->_tmp_format->_BIFF_version = $version;
+ $this->_url_format->_BIFF_version = $version;
+ $this->_parser->_BIFF_version = $version;
+
+ $total_worksheets = count($this->_worksheets);
+ // change version for all worksheets too
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ $this->_worksheets[$i]->_BIFF_version = $version;
+ }
+
+ $total_formats = count($this->_formats);
+ // change version for all formats too
+ for ($i = 0; $i < $total_formats; $i++) {
+ $this->_formats[$i]->_BIFF_version = $version;
+ }
+ }
+ }
+
+ /**
+ * Set the country identifier for the workbook
+ *
+ * @access public
+ * @param integer $code Is the international calling country code for the
+ * chosen country.
+ */
+ function setCountry($code)
+ {
+ $this->_country_code = $code;
+ }
+
+ /**
+ * Add a new worksheet to the Excel workbook.
+ * If no name is given the name of the worksheet will be Sheeti$i, with
+ * $i in [1..].
+ *
+ * @access public
+ * @param string $name the optional name of the worksheet
+ * @return mixed reference to a worksheet object on success, PEAR_Error
+ * on failure
+ */
+ function &addWorksheet($name = '')
+ {
+ $index = count($this->_worksheets);
+ $sheetname = $this->_sheetname;
+
+ if ($name == '') {
+ $name = $sheetname.($index+1);
+ }
+
+ // Check that sheetname is <= 31 chars (Excel limit before BIFF8).
+ if ($this->_BIFF_version != 0x0600)
+ {
+ if (strlen($name) > 31) {
+ return $this->raiseError("Sheetname $name must be <= 31 chars");
+ }
+ }
+
+ // Check that the worksheet name doesn't already exist: a fatal Excel error.
+ $total_worksheets = count($this->_worksheets);
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ if ($this->_worksheets[$i]->getName() == $name) {
+ return $this->raiseError("Worksheet '$name' already exists");
+ }
+ }
+
+ $worksheet = new Spreadsheet_Excel_Writer_Worksheet($this->_BIFF_version,
+ $name, $index,
+ $this->_activesheet, $this->_firstsheet,
+ $this->_str_total, $this->_str_unique,
+ $this->_str_table, $this->_url_format,
+ $this->_parser);
+
+ $this->_worksheets[$index] = &$worksheet; // Store ref for iterator
+ $this->_sheetnames[$index] = $name; // Store EXTERNSHEET names
+ $this->_parser->setExtSheet($name, $index); // Register worksheet name with parser
+ return $worksheet;
+ }
+
+ /**
+ * Add a new format to the Excel workbook.
+ * Also, pass any properties to the Format constructor.
+ *
+ * @access public
+ * @param array $properties array with properties for initializing the format.
+ * @return &Spreadsheet_Excel_Writer_Format reference to an Excel Format
+ */
+ function &addFormat($properties = array())
+ {
+ $format = new Spreadsheet_Excel_Writer_Format($this->_BIFF_version, $this->_xf_index, $properties);
+ $this->_xf_index += 1;
+ $this->_formats[] = &$format;
+ return $format;
+ }
+
+ /**
+ * Create new validator.
+ *
+ * @access public
+ * @return &Spreadsheet_Excel_Writer_Validator reference to a Validator
+ */
+ function &addValidator()
+ {
+ include_once 'Spreadsheet/Excel/Writer/Validator.php';
+ /* FIXME: check for successful inclusion*/
+ $valid = new Spreadsheet_Excel_Writer_Validator($this->_parser);
+ return $valid;
+ }
+
+ /**
+ * Change the RGB components of the elements in the colour palette.
+ *
+ * @access public
+ * @param integer $index colour index
+ * @param integer $red red RGB value [0-255]
+ * @param integer $green green RGB value [0-255]
+ * @param integer $blue blue RGB value [0-255]
+ * @return integer The palette index for the custom color
+ */
+ function setCustomColor($index, $red, $green, $blue)
+ {
+ // Match a HTML #xxyyzz style parameter
+ /*if (defined $_[1] and $_[1] =~ /^#(\w\w)(\w\w)(\w\w)/ ) {
+ @_ = ($_[0], hex $1, hex $2, hex $3);
+ }*/
+
+ // Check that the colour index is the right range
+ if ($index < 8 or $index > 64) {
+ // TODO: assign real error codes
+ return $this->raiseError("Color index $index outside range: 8 <= index <= 64");
+ }
+
+ // Check that the colour components are in the right range
+ if (($red < 0 or $red > 255) ||
+ ($green < 0 or $green > 255) ||
+ ($blue < 0 or $blue > 255))
+ {
+ return $this->raiseError("Color component outside range: 0 <= color <= 255");
+ }
+
+ $index -= 8; // Adjust colour index (wingless dragonfly)
+
+ // Set the RGB value
+ $this->_palette[$index] = array($red, $green, $blue, 0);
+ return($index + 8);
+ }
+
+ /**
+ * Sets the colour palette to the Excel 97+ default.
+ *
+ * @access private
+ */
+ function _setPaletteXl97()
+ {
+ $this->_palette = array(
+ array(0x00, 0x00, 0x00, 0x00), // 8
+ array(0xff, 0xff, 0xff, 0x00), // 9
+ array(0xff, 0x00, 0x00, 0x00), // 10
+ array(0x00, 0xff, 0x00, 0x00), // 11
+ array(0x00, 0x00, 0xff, 0x00), // 12
+ array(0xff, 0xff, 0x00, 0x00), // 13
+ array(0xff, 0x00, 0xff, 0x00), // 14
+ array(0x00, 0xff, 0xff, 0x00), // 15
+ array(0x80, 0x00, 0x00, 0x00), // 16
+ array(0x00, 0x80, 0x00, 0x00), // 17
+ array(0x00, 0x00, 0x80, 0x00), // 18
+ array(0x80, 0x80, 0x00, 0x00), // 19
+ array(0x80, 0x00, 0x80, 0x00), // 20
+ array(0x00, 0x80, 0x80, 0x00), // 21
+ array(0xc0, 0xc0, 0xc0, 0x00), // 22
+ array(0x80, 0x80, 0x80, 0x00), // 23
+ array(0x99, 0x99, 0xff, 0x00), // 24
+ array(0x99, 0x33, 0x66, 0x00), // 25
+ array(0xff, 0xff, 0xcc, 0x00), // 26
+ array(0xcc, 0xff, 0xff, 0x00), // 27
+ array(0x66, 0x00, 0x66, 0x00), // 28
+ array(0xff, 0x80, 0x80, 0x00), // 29
+ array(0x00, 0x66, 0xcc, 0x00), // 30
+ array(0xcc, 0xcc, 0xff, 0x00), // 31
+ array(0x00, 0x00, 0x80, 0x00), // 32
+ array(0xff, 0x00, 0xff, 0x00), // 33
+ array(0xff, 0xff, 0x00, 0x00), // 34
+ array(0x00, 0xff, 0xff, 0x00), // 35
+ array(0x80, 0x00, 0x80, 0x00), // 36
+ array(0x80, 0x00, 0x00, 0x00), // 37
+ array(0x00, 0x80, 0x80, 0x00), // 38
+ array(0x00, 0x00, 0xff, 0x00), // 39
+ array(0x00, 0xcc, 0xff, 0x00), // 40
+ array(0xcc, 0xff, 0xff, 0x00), // 41
+ array(0xcc, 0xff, 0xcc, 0x00), // 42
+ array(0xff, 0xff, 0x99, 0x00), // 43
+ array(0x99, 0xcc, 0xff, 0x00), // 44
+ array(0xff, 0x99, 0xcc, 0x00), // 45
+ array(0xcc, 0x99, 0xff, 0x00), // 46
+ array(0xff, 0xcc, 0x99, 0x00), // 47
+ array(0x33, 0x66, 0xff, 0x00), // 48
+ array(0x33, 0xcc, 0xcc, 0x00), // 49
+ array(0x99, 0xcc, 0x00, 0x00), // 50
+ array(0xff, 0xcc, 0x00, 0x00), // 51
+ array(0xff, 0x99, 0x00, 0x00), // 52
+ array(0xff, 0x66, 0x00, 0x00), // 53
+ array(0x66, 0x66, 0x99, 0x00), // 54
+ array(0x96, 0x96, 0x96, 0x00), // 55
+ array(0x00, 0x33, 0x66, 0x00), // 56
+ array(0x33, 0x99, 0x66, 0x00), // 57
+ array(0x00, 0x33, 0x00, 0x00), // 58
+ array(0x33, 0x33, 0x00, 0x00), // 59
+ array(0x99, 0x33, 0x00, 0x00), // 60
+ array(0x99, 0x33, 0x66, 0x00), // 61
+ array(0x33, 0x33, 0x99, 0x00), // 62
+ array(0x33, 0x33, 0x33, 0x00), // 63
+ );
+ }
+
+ /**
+ * Assemble worksheets into a workbook and send the BIFF data to an OLE
+ * storage.
+ *
+ * @access private
+ * @return mixed true on success. PEAR_Error on failure
+ */
+ function _storeWorkbook()
+ {
+ // Ensure that at least one worksheet has been selected.
+ if ($this->_activesheet == 0) {
+ $this->_worksheets[0]->selected = 1;
+ }
+
+ // Calculate the number of selected worksheet tabs and call the finalization
+ // methods for each worksheet
+ $total_worksheets = count($this->_worksheets);
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ if ($this->_worksheets[$i]->selected) {
+ $this->_selected++;
+ }
+ $this->_worksheets[$i]->close($this->_sheetnames);
+ }
+
+ // Add Workbook globals
+ $this->_storeBof(0x0005);
+ $this->_storeCodepage();
+ if ($this->_BIFF_version == 0x0600) {
+ $this->_storeWindow1();
+ }
+ if ($this->_BIFF_version == 0x0500) {
+ $this->_storeExterns(); // For print area and repeat rows
+ }
+ $this->_storeNames(); // For print area and repeat rows
+ if ($this->_BIFF_version == 0x0500) {
+ $this->_storeWindow1();
+ }
+ $this->_storeDatemode();
+ $this->_storeAllFonts();
+ $this->_storeAllNumFormats();
+ $this->_storeAllXfs();
+ $this->_storeAllStyles();
+ $this->_storePalette();
+ $this->_calcSheetOffsets();
+
+ // Add BOUNDSHEET records
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ $this->_storeBoundsheet($this->_worksheets[$i]->name,$this->_worksheets[$i]->offset);
+ }
+
+ if ($this->_country_code != -1) {
+ $this->_storeCountry();
+ }
+
+ if ($this->_BIFF_version == 0x0600) {
+ //$this->_storeSupbookInternal();
+ /* TODO: store external SUPBOOK records and XCT and CRN records
+ in case of external references for BIFF8 */
+ //$this->_storeExternsheetBiff8();
+ $this->_storeSharedStringsTable();
+ }
+
+ // End Workbook globals
+ $this->_storeEof();
+
+ // Store the workbook in an OLE container
+ $res = $this->_storeOLEFile();
+ if ($this->isError($res)) {
+ return $this->raiseError($res->getMessage());
+ }
+ return true;
+ }
+
+ /**
+ * Sets the temp dir used for storing the OLE file
+ *
+ * @access public
+ * @param string $dir The dir to be used as temp dir
+ * @return true if given dir is valid, false otherwise
+ */
+ function setTempDir($dir)
+ {
+ if (is_dir($dir)) {
+ $this->_tmp_dir = $dir;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Store the workbook in an OLE container
+ *
+ * @access private
+ * @return mixed true on success. PEAR_Error on failure
+ */
+ function _storeOLEFile()
+ {
+ $OLE = new OLE_PPS_File(OLE::Asc2Ucs('Book'));
+ if ($this->_tmp_dir != '') {
+ $OLE->setTempDir($this->_tmp_dir);
+ }
+ $res = $OLE->init();
+ if ($this->isError($res)) {
+ return $this->raiseError("OLE Error: ".$res->getMessage());
+ }
+ $OLE->append($this->_data);
+
+ $total_worksheets = count($this->_worksheets);
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ while ($tmp = $this->_worksheets[$i]->getData()) {
+ $OLE->append($tmp);
+ }
+ }
+
+ $root = new OLE_PPS_Root(time(), time(), array($OLE));
+ if ($this->_tmp_dir != '') {
+ $root->setTempDir($this->_tmp_dir);
+ }
+
+ $res = $root->save($this->_filename);
+ if ($this->isError($res)) {
+ return $this->raiseError("OLE Error: ".$res->getMessage());
+ }
+ return true;
+ }
+
+ /**
+ * Calculate offsets for Worksheet BOF records.
+ *
+ * @access private
+ */
+ function _calcSheetOffsets()
+ {
+ if ($this->_BIFF_version == 0x0600) {
+ $boundsheet_length = 12; // fixed length for a BOUNDSHEET record
+ } else {
+ $boundsheet_length = 11;
+ }
+ $EOF = 4;
+ $offset = $this->_datasize;
+
+ if ($this->_BIFF_version == 0x0600) {
+ // add the length of the SST
+ /* TODO: check this works for a lot of strings (> 8224 bytes) */
+ $offset += $this->_calculateSharedStringsSizes();
+ if ($this->_country_code != -1) {
+ $offset += 8; // adding COUNTRY record
+ }
+ // add the lenght of SUPBOOK, EXTERNSHEET and NAME records
+ //$offset += 8; // FIXME: calculate real value when storing the records
+ }
+ $total_worksheets = count($this->_worksheets);
+ // add the length of the BOUNDSHEET records
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ $offset += $boundsheet_length + strlen($this->_worksheets[$i]->name);
+ }
+ $offset += $EOF;
+
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ $this->_worksheets[$i]->offset = $offset;
+ $offset += $this->_worksheets[$i]->_datasize;
+ }
+ $this->_biffsize = $offset;
+ }
+
+ /**
+ * Store the Excel FONT records.
+ *
+ * @access private
+ */
+ function _storeAllFonts()
+ {
+ // tmp_format is added by the constructor. We use this to write the default XF's
+ $format = $this->_tmp_format;
+ $font = $format->getFont();
+
+ // Note: Fonts are 0-indexed. According to the SDK there is no index 4,
+ // so the following fonts are 0, 1, 2, 3, 5
+ //
+ for ($i = 1; $i <= 5; $i++){
+ $this->_append($font);
+ }
+
+ // Iterate through the XF objects and write a FONT record if it isn't the
+ // same as the default FONT and if it hasn't already been used.
+ //
+ $fonts = array();
+ $index = 6; // The first user defined FONT
+
+ $key = $format->getFontKey(); // The default font from _tmp_format
+ $fonts[$key] = 0; // Index of the default font
+
+ $total_formats = count($this->_formats);
+ for ($i = 0; $i < $total_formats; $i++) {
+ $key = $this->_formats[$i]->getFontKey();
+ if (isset($fonts[$key])) {
+ // FONT has already been used
+ $this->_formats[$i]->font_index = $fonts[$key];
+ } else {
+ // Add a new FONT record
+ $fonts[$key] = $index;
+ $this->_formats[$i]->font_index = $index;
+ $index++;
+ $font = $this->_formats[$i]->getFont();
+ $this->_append($font);
+ }
+ }
+ }
+
+ /**
+ * Store user defined numerical formats i.e. FORMAT records
+ *
+ * @access private
+ */
+ function _storeAllNumFormats()
+ {
+ // Leaning num_format syndrome
+ $hash_num_formats = array();
+ $num_formats = array();
+ $index = 164;
+
+ // Iterate through the XF objects and write a FORMAT record if it isn't a
+ // built-in format type and if the FORMAT string hasn't already been used.
+ $total_formats = count($this->_formats);
+ for ($i = 0; $i < $total_formats; $i++) {
+ $num_format = $this->_formats[$i]->_num_format;
+
+ // Check if $num_format is an index to a built-in format.
+ // Also check for a string of zeros, which is a valid format string
+ // but would evaluate to zero.
+ //
+ if (!preg_match("/^0+\d/", $num_format)) {
+ if (preg_match("/^\d+$/", $num_format)) { // built-in format
+ continue;
+ }
+ }
+
+ if (isset($hash_num_formats[$num_format])) {
+ // FORMAT has already been used
+ $this->_formats[$i]->_num_format = $hash_num_formats[$num_format];
+ } else{
+ // Add a new FORMAT
+ $hash_num_formats[$num_format] = $index;
+ $this->_formats[$i]->_num_format = $index;
+ array_push($num_formats,$num_format);
+ $index++;
+ }
+ }
+
+ // Write the new FORMAT records starting from 0xA4
+ $index = 164;
+ foreach ($num_formats as $num_format) {
+ $this->_storeNumFormat($num_format,$index);
+ $index++;
+ }
+ }
+
+ /**
+ * Write all XF records.
+ *
+ * @access private
+ */
+ function _storeAllXfs()
+ {
+ // _tmp_format is added by the constructor. We use this to write the default XF's
+ // The default font index is 0
+ //
+ $format = $this->_tmp_format;
+ for ($i = 0; $i <= 14; $i++) {
+ $xf = $format->getXf('style'); // Style XF
+ $this->_append($xf);
+ }
+
+ $xf = $format->getXf('cell'); // Cell XF
+ $this->_append($xf);
+
+ // User defined XFs
+ $total_formats = count($this->_formats);
+ for ($i = 0; $i < $total_formats; $i++) {
+ $xf = $this->_formats[$i]->getXf('cell');
+ $this->_append($xf);
+ }
+ }
+
+ /**
+ * Write all STYLE records.
+ *
+ * @access private
+ */
+ function _storeAllStyles()
+ {
+ $this->_storeStyle();
+ }
+
+ /**
+ * Write the EXTERNCOUNT and EXTERNSHEET records. These are used as indexes for
+ * the NAME records.
+ *
+ * @access private
+ */
+ function _storeExterns()
+ {
+ // Create EXTERNCOUNT with number of worksheets
+ $this->_storeExterncount(count($this->_worksheets));
+
+ // Create EXTERNSHEET for each worksheet
+ foreach ($this->_sheetnames as $sheetname) {
+ $this->_storeExternsheet($sheetname);
+ }
+ }
+
+ /**
+ * Write the NAME record to define the print area and the repeat rows and cols.
+ *
+ * @access private
+ */
+ function _storeNames()
+ {
+ // Create the print area NAME records
+ $total_worksheets = count($this->_worksheets);
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ // Write a Name record if the print area has been defined
+ if (isset($this->_worksheets[$i]->print_rowmin)) {
+ $this->_storeNameShort(
+ $this->_worksheets[$i]->index,
+ 0x06, // NAME type
+ $this->_worksheets[$i]->print_rowmin,
+ $this->_worksheets[$i]->print_rowmax,
+ $this->_worksheets[$i]->print_colmin,
+ $this->_worksheets[$i]->print_colmax
+ );
+ }
+ }
+
+ // Create the print title NAME records
+ $total_worksheets = count($this->_worksheets);
+ for ($i = 0; $i < $total_worksheets; $i++) {
+ $rowmin = $this->_worksheets[$i]->title_rowmin;
+ $rowmax = $this->_worksheets[$i]->title_rowmax;
+ $colmin = $this->_worksheets[$i]->title_colmin;
+ $colmax = $this->_worksheets[$i]->title_colmax;
+
+ // Determine if row + col, row, col or nothing has been defined
+ // and write the appropriate record
+ //
+ if (isset($rowmin) && isset($colmin)) {
+ // Row and column titles have been defined.
+ // Row title has been defined.
+ $this->_storeNameLong(
+ $this->_worksheets[$i]->index,
+ 0x07, // NAME type
+ $rowmin,
+ $rowmax,
+ $colmin,
+ $colmax
+ );
+ } elseif (isset($rowmin)) {
+ // Row title has been defined.
+ $this->_storeNameShort(
+ $this->_worksheets[$i]->index,
+ 0x07, // NAME type
+ $rowmin,
+ $rowmax,
+ 0x00,
+ 0xff
+ );
+ } elseif (isset($colmin)) {
+ // Column title has been defined.
+ $this->_storeNameShort(
+ $this->_worksheets[$i]->index,
+ 0x07, // NAME type
+ 0x0000,
+ 0x3fff,
+ $colmin,
+ $colmax
+ );
+ } else {
+ // Print title hasn't been defined.
+ }
+ }
+ }
+
+
+
+
+ /******************************************************************************
+ *
+ * BIFF RECORDS
+ *
+ */
+
+ /**
+ * Stores the CODEPAGE biff record.
+ *
+ * @access private
+ */
+ function _storeCodepage()
+ {
+ $record = 0x0042; // Record identifier
+ $length = 0x0002; // Number of bytes to follow
+ $cv = $this->_codepage; // The code page
+
+ $header = pack('vv', $record, $length);
+ $data = pack('v', $cv);
+
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Write Excel BIFF WINDOW1 record.
+ *
+ * @access private
+ */
+ function _storeWindow1()
+ {
+ $record = 0x003D; // Record identifier
+ $length = 0x0012; // Number of bytes to follow
+
+ $xWn = 0x0000; // Horizontal position of window
+ $yWn = 0x0000; // Vertical position of window
+ $dxWn = 0x25BC; // Width of window
+ $dyWn = 0x1572; // Height of window
+
+ $grbit = 0x0038; // Option flags
+ $ctabsel = $this->_selected; // Number of workbook tabs selected
+ $wTabRatio = 0x0258; // Tab to scrollbar ratio
+
+ $itabFirst = $this->_firstsheet; // 1st displayed worksheet
+ $itabCur = $this->_activesheet; // Active worksheet
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvvvvvvv", $xWn, $yWn, $dxWn, $dyWn,
+ $grbit,
+ $itabCur, $itabFirst,
+ $ctabsel, $wTabRatio);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Writes Excel BIFF BOUNDSHEET record.
+ * FIXME: inconsistent with BIFF documentation
+ *
+ * @param string $sheetname Worksheet name
+ * @param integer $offset Location of worksheet BOF
+ * @access private
+ */
+ function _storeBoundsheet($sheetname,$offset)
+ {
+ $record = 0x0085; // Record identifier
+ if ($this->_BIFF_version == 0x0600) {
+ $length = 0x08 + strlen($sheetname); // Number of bytes to follow
+ } else {
+ $length = 0x07 + strlen($sheetname); // Number of bytes to follow
+ }
+
+ $grbit = 0x0000; // Visibility and sheet type
+ $cch = strlen($sheetname); // Length of sheet name
+
+ $header = pack("vv", $record, $length);
+ if ($this->_BIFF_version == 0x0600) {
+ $data = pack("Vvv", $offset, $grbit, $cch);
+ } else {
+ $data = pack("VvC", $offset, $grbit, $cch);
+ }
+ $this->_append($header.$data.$sheetname);
+ }
+
+ /**
+ * Write Internal SUPBOOK record
+ *
+ * @access private
+ */
+ function _storeSupbookInternal()
+ {
+ $record = 0x01AE; // Record identifier
+ $length = 0x0004; // Bytes to follow
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vv", count($this->_worksheets), 0x0104);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Writes the Excel BIFF EXTERNSHEET record. These references are used by
+ * formulas.
+ *
+ * @param string $sheetname Worksheet name
+ * @access private
+ */
+ function _storeExternsheetBiff8()
+ {
+ $total_references = count($this->_parser->_references);
+ $record = 0x0017; // Record identifier
+ $length = 2 + 6 * $total_references; // Number of bytes to follow
+
+ $supbook_index = 0; // FIXME: only using internal SUPBOOK record
+ $header = pack("vv", $record, $length);
+ $data = pack('v', $total_references);
+ for ($i = 0; $i < $total_references; $i++) {
+ $data .= $this->_parser->_references[$i];
+ }
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Write Excel BIFF STYLE records.
+ *
+ * @access private
+ */
+ function _storeStyle()
+ {
+ $record = 0x0293; // Record identifier
+ $length = 0x0004; // Bytes to follow
+
+ $ixfe = 0x8000; // Index to style XF
+ $BuiltIn = 0x00; // Built-in style
+ $iLevel = 0xff; // Outline style level
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vCC", $ixfe, $BuiltIn, $iLevel);
+ $this->_append($header . $data);
+ }
+
+
+ /**
+ * Writes Excel FORMAT record for non "built-in" numerical formats.
+ *
+ * @param string $format Custom format string
+ * @param integer $ifmt Format index code
+ * @access private
+ */
+ function _storeNumFormat($format, $ifmt)
+ {
+ $record = 0x041E; // Record identifier
+
+ if ($this->_BIFF_version == 0x0600) {
+ $length = 5 + strlen($format); // Number of bytes to follow
+ $encoding = 0x0;
+ } elseif ($this->_BIFF_version == 0x0500) {
+ $length = 3 + strlen($format); // Number of bytes to follow
+ }
+
+ $cch = strlen($format); // Length of format string
+
+ $header = pack("vv", $record, $length);
+ if ($this->_BIFF_version == 0x0600) {
+ $data = pack("vvC", $ifmt, $cch, $encoding);
+ } elseif ($this->_BIFF_version == 0x0500) {
+ $data = pack("vC", $ifmt, $cch);
+ }
+ $this->_append($header . $data . $format);
+ }
+
+ /**
+ * Write DATEMODE record to indicate the date system in use (1904 or 1900).
+ *
+ * @access private
+ */
+ function _storeDatemode()
+ {
+ $record = 0x0022; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $f1904 = $this->_1904; // Flag for 1904 date system
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $f1904);
+ $this->_append($header . $data);
+ }
+
+
+ /**
+ * Write BIFF record EXTERNCOUNT to indicate the number of external sheet
+ * references in the workbook.
+ *
+ * Excel only stores references to external sheets that are used in NAME.
+ * The workbook NAME record is required to define the print area and the repeat
+ * rows and columns.
+ *
+ * A similar method is used in Worksheet.php for a slightly different purpose.
+ *
+ * @param integer $cxals Number of external references
+ * @access private
+ */
+ function _storeExterncount($cxals)
+ {
+ $record = 0x0016; // Record identifier
+ $length = 0x0002; // Number of bytes to follow
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $cxals);
+ $this->_append($header . $data);
+ }
+
+
+ /**
+ * Writes the Excel BIFF EXTERNSHEET record. These references are used by
+ * formulas. NAME record is required to define the print area and the repeat
+ * rows and columns.
+ *
+ * A similar method is used in Worksheet.php for a slightly different purpose.
+ *
+ * @param string $sheetname Worksheet name
+ * @access private
+ */
+ function _storeExternsheet($sheetname)
+ {
+ $record = 0x0017; // Record identifier
+ $length = 0x02 + strlen($sheetname); // Number of bytes to follow
+
+ $cch = strlen($sheetname); // Length of sheet name
+ $rgch = 0x03; // Filename encoding
+
+ $header = pack("vv", $record, $length);
+ $data = pack("CC", $cch, $rgch);
+ $this->_append($header . $data . $sheetname);
+ }
+
+
+ /**
+ * Store the NAME record in the short format that is used for storing the print
+ * area, repeat rows only and repeat columns only.
+ *
+ * @param integer $index Sheet index
+ * @param integer $type Built-in name type
+ * @param integer $rowmin Start row
+ * @param integer $rowmax End row
+ * @param integer $colmin Start colum
+ * @param integer $colmax End column
+ * @access private
+ */
+ function _storeNameShort($index, $type, $rowmin, $rowmax, $colmin, $colmax)
+ {
+ $record = 0x0018; // Record identifier
+ $length = 0x0024; // Number of bytes to follow
+
+ $grbit = 0x0020; // Option flags
+ $chKey = 0x00; // Keyboard shortcut
+ $cch = 0x01; // Length of text name
+ $cce = 0x0015; // Length of text definition
+ $ixals = $index + 1; // Sheet index
+ $itab = $ixals; // Equal to ixals
+ $cchCustMenu = 0x00; // Length of cust menu text
+ $cchDescription = 0x00; // Length of description text
+ $cchHelptopic = 0x00; // Length of help topic text
+ $cchStatustext = 0x00; // Length of status bar text
+ $rgch = $type; // Built-in name type
+
+ $unknown03 = 0x3b;
+ $unknown04 = 0xffff-$index;
+ $unknown05 = 0x0000;
+ $unknown06 = 0x0000;
+ $unknown07 = 0x1087;
+ $unknown08 = 0x8005;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $grbit);
+ $data .= pack("C", $chKey);
+ $data .= pack("C", $cch);
+ $data .= pack("v", $cce);
+ $data .= pack("v", $ixals);
+ $data .= pack("v", $itab);
+ $data .= pack("C", $cchCustMenu);
+ $data .= pack("C", $cchDescription);
+ $data .= pack("C", $cchHelptopic);
+ $data .= pack("C", $cchStatustext);
+ $data .= pack("C", $rgch);
+ $data .= pack("C", $unknown03);
+ $data .= pack("v", $unknown04);
+ $data .= pack("v", $unknown05);
+ $data .= pack("v", $unknown06);
+ $data .= pack("v", $unknown07);
+ $data .= pack("v", $unknown08);
+ $data .= pack("v", $index);
+ $data .= pack("v", $index);
+ $data .= pack("v", $rowmin);
+ $data .= pack("v", $rowmax);
+ $data .= pack("C", $colmin);
+ $data .= pack("C", $colmax);
+ $this->_append($header . $data);
+ }
+
+
+ /**
+ * Store the NAME record in the long format that is used for storing the repeat
+ * rows and columns when both are specified. This shares a lot of code with
+ * _storeNameShort() but we use a separate method to keep the code clean.
+ * Code abstraction for reuse can be carried too far, and I should know. ;-)
+ *
+ * @param integer $index Sheet index
+ * @param integer $type Built-in name type
+ * @param integer $rowmin Start row
+ * @param integer $rowmax End row
+ * @param integer $colmin Start colum
+ * @param integer $colmax End column
+ * @access private
+ */
+ function _storeNameLong($index, $type, $rowmin, $rowmax, $colmin, $colmax)
+ {
+ $record = 0x0018; // Record identifier
+ $length = 0x003d; // Number of bytes to follow
+ $grbit = 0x0020; // Option flags
+ $chKey = 0x00; // Keyboard shortcut
+ $cch = 0x01; // Length of text name
+ $cce = 0x002e; // Length of text definition
+ $ixals = $index + 1; // Sheet index
+ $itab = $ixals; // Equal to ixals
+ $cchCustMenu = 0x00; // Length of cust menu text
+ $cchDescription = 0x00; // Length of description text
+ $cchHelptopic = 0x00; // Length of help topic text
+ $cchStatustext = 0x00; // Length of status bar text
+ $rgch = $type; // Built-in name type
+
+ $unknown01 = 0x29;
+ $unknown02 = 0x002b;
+ $unknown03 = 0x3b;
+ $unknown04 = 0xffff-$index;
+ $unknown05 = 0x0000;
+ $unknown06 = 0x0000;
+ $unknown07 = 0x1087;
+ $unknown08 = 0x8008;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $grbit);
+ $data .= pack("C", $chKey);
+ $data .= pack("C", $cch);
+ $data .= pack("v", $cce);
+ $data .= pack("v", $ixals);
+ $data .= pack("v", $itab);
+ $data .= pack("C", $cchCustMenu);
+ $data .= pack("C", $cchDescription);
+ $data .= pack("C", $cchHelptopic);
+ $data .= pack("C", $cchStatustext);
+ $data .= pack("C", $rgch);
+ $data .= pack("C", $unknown01);
+ $data .= pack("v", $unknown02);
+ // Column definition
+ $data .= pack("C", $unknown03);
+ $data .= pack("v", $unknown04);
+ $data .= pack("v", $unknown05);
+ $data .= pack("v", $unknown06);
+ $data .= pack("v", $unknown07);
+ $data .= pack("v", $unknown08);
+ $data .= pack("v", $index);
+ $data .= pack("v", $index);
+ $data .= pack("v", 0x0000);
+ $data .= pack("v", 0x3fff);
+ $data .= pack("C", $colmin);
+ $data .= pack("C", $colmax);
+ // Row definition
+ $data .= pack("C", $unknown03);
+ $data .= pack("v", $unknown04);
+ $data .= pack("v", $unknown05);
+ $data .= pack("v", $unknown06);
+ $data .= pack("v", $unknown07);
+ $data .= pack("v", $unknown08);
+ $data .= pack("v", $index);
+ $data .= pack("v", $index);
+ $data .= pack("v", $rowmin);
+ $data .= pack("v", $rowmax);
+ $data .= pack("C", 0x00);
+ $data .= pack("C", 0xff);
+ // End of data
+ $data .= pack("C", 0x10);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Stores the COUNTRY record for localization
+ *
+ * @access private
+ */
+ function _storeCountry()
+ {
+ $record = 0x008C; // Record identifier
+ $length = 4; // Number of bytes to follow
+
+ $header = pack('vv', $record, $length);
+ /* using the same country code always for simplicity */
+ $data = pack('vv', $this->_country_code, $this->_country_code);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Stores the PALETTE biff record.
+ *
+ * @access private
+ */
+ function _storePalette()
+ {
+ $aref = $this->_palette;
+
+ $record = 0x0092; // Record identifier
+ $length = 2 + 4 * count($aref); // Number of bytes to follow
+ $ccv = count($aref); // Number of RGB values to follow
+ $data = ''; // The RGB data
+
+ // Pack the RGB data
+ foreach ($aref as $color) {
+ foreach ($color as $byte) {
+ $data .= pack("C",$byte);
+ }
+ }
+
+ $header = pack("vvv", $record, $length, $ccv);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Calculate
+ * Handling of the SST continue blocks is complicated by the need to include an
+ * additional continuation byte depending on whether the string is split between
+ * blocks or whether it starts at the beginning of the block. (There are also
+ * additional complications that will arise later when/if Rich Strings are
+ * supported).
+ *
+ * @access private
+ */
+ function _calculateSharedStringsSizes()
+ {
+ /* Iterate through the strings to calculate the CONTINUE block sizes.
+ For simplicity we use the same size for the SST and CONTINUE records:
+ 8228 : Maximum Excel97 block size
+ -4 : Length of block header
+ -8 : Length of additional SST header information
+ = 8216
+ */
+ $continue_limit = 8216;
+ $block_length = 0;
+ $written = 0;
+ $this->_block_sizes = array();
+ $continue = 0;
+
+ foreach (array_keys($this->_str_table) as $string) {
+ $string_length = strlen($string);
+
+ // Block length is the total length of the strings that will be
+ // written out in a single SST or CONTINUE block.
+ $block_length += $string_length;
+
+ // We can write the string if it doesn't cross a CONTINUE boundary
+ if ($block_length < $continue_limit) {
+ $written += $string_length;
+ continue;
+ }
+
+ // Deal with the cases where the next string to be written will exceed
+ // the CONTINUE boundary. If the string is very long it may need to be
+ // written in more than one CONTINUE record.
+ while ($block_length >= $continue_limit) {
+
+ // We need to avoid the case where a string is continued in the first
+ // n bytes that contain the string header information.
+ $header_length = 3; // Min string + header size -1
+ $space_remaining = $continue_limit - $written - $continue;
+
+
+ /* TODO: Unicode data should only be split on char (2 byte)
+ boundaries. Therefore, in some cases we need to reduce the
+ amount of available
+ */
+
+ if ($space_remaining > $header_length) {
+ // Write as much as possible of the string in the current block
+ $written += $space_remaining;
+
+ // Reduce the current block length by the amount written
+ $block_length -= $continue_limit - $continue;
+
+ // Store the max size for this block
+ $this->_block_sizes[] = $continue_limit;
+
+ // If the current string was split then the next CONTINUE block
+ // should have the string continue flag (grbit) set unless the
+ // split string fits exactly into the remaining space.
+ if ($block_length > 0) {
+ $continue = 1;
+ } else {
+ $continue = 0;
+ }
+ } else {
+ // Store the max size for this block
+ $this->_block_sizes[] = $written + $continue;
+
+ // Not enough space to start the string in the current block
+ $block_length -= $continue_limit - $space_remaining - $continue;
+ $continue = 0;
+
+ }
+
+ // If the string (or substr) is small enough we can write it in the
+ // new CONTINUE block. Else, go through the loop again to write it in
+ // one or more CONTINUE blocks
+ if ($block_length < $continue_limit) {
+ $written = $block_length;
+ } else {
+ $written = 0;
+ }
+ }
+ }
+
+ // Store the max size for the last block unless it is empty
+ if ($written + $continue) {
+ $this->_block_sizes[] = $written + $continue;
+ }
+
+
+ /* Calculate the total length of the SST and associated CONTINUEs (if any).
+ The SST record will have a length even if it contains no strings.
+ This length is required to set the offsets in the BOUNDSHEET records since
+ they must be written before the SST records
+ */
+ $total_offset = array_sum($this->_block_sizes);
+ // SST information
+ $total_offset += 8;
+ if (!empty($this->_block_sizes)) {
+ $total_offset += (count($this->_block_sizes)) * 4; // add CONTINUE headers
+ }
+ return $total_offset;
+ }
+
+ /**
+ * Write all of the workbooks strings into an indexed array.
+ * See the comments in _calculate_shared_string_sizes() for more information.
+ *
+ * The Excel documentation says that the SST record should be followed by an
+ * EXTSST record. The EXTSST record is a hash table that is used to optimise
+ * access to SST. However, despite the documentation it doesn't seem to be
+ * required so we will ignore it.
+ *
+ * @access private
+ */
+ function _storeSharedStringsTable()
+ {
+ $record = 0x00fc; // Record identifier
+ // sizes are upside down
+ $this->_block_sizes = array_reverse($this->_block_sizes);
+ $length = array_pop($this->_block_sizes) + 8; // First block size plus SST information
+
+ // Write the SST block header information
+ $header = pack("vv", $record, $length);
+ $data = pack("VV", $this->_str_total, $this->_str_unique);
+ $this->_append($header . $data);
+
+
+ // Iterate through the strings to calculate the CONTINUE block sizes
+ $continue_limit = 8216;
+ $block_length = 0;
+ $written = 0;
+ $continue = 0;
+
+
+ /* TODO: not good for performance */
+ foreach (array_keys($this->_str_table) as $string) {
+
+ $string_length = strlen($string);
+ $encoding = 0; // assume there are no Unicode strings
+ $split_string = 0;
+
+ // Block length is the total length of the strings that will be
+ // written out in a single SST or CONTINUE block.
+ //
+ $block_length += $string_length;
+
+
+ // We can write the string if it doesn't cross a CONTINUE boundary
+ if ($block_length < $continue_limit) {
+ $this->_append($string);
+ $written += $string_length;
+ continue;
+ }
+
+ // Deal with the cases where the next string to be written will exceed
+ // the CONTINUE boundary. If the string is very long it may need to be
+ // written in more than one CONTINUE record.
+ //
+ while ($block_length >= $continue_limit) {
+
+ // We need to avoid the case where a string is continued in the first
+ // n bytes that contain the string header information.
+ //
+ $header_length = 3; // Min string + header size -1
+ $space_remaining = $continue_limit - $written - $continue;
+
+
+ // Unicode data should only be split on char (2 byte) boundaries.
+ // Therefore, in some cases we need to reduce the amount of available
+
+ if ($space_remaining > $header_length) {
+ // Write as much as possible of the string in the current block
+ $tmp = substr($string, 0, $space_remaining);
+ $this->_append($tmp);
+
+ // The remainder will be written in the next block(s)
+ $string = substr($string, $space_remaining);
+
+ // Reduce the current block length by the amount written
+ $block_length -= $continue_limit - $continue;
+
+ // If the current string was split then the next CONTINUE block
+ // should have the string continue flag (grbit) set unless the
+ // split string fits exactly into the remaining space.
+ //
+ if ($block_length > 0) {
+ $continue = 1;
+ } else {
+ $continue = 0;
+ }
+ } else {
+ // Not enough space to start the string in the current block
+ $block_length -= $continue_limit - $space_remaining - $continue;
+ $continue = 0;
+ }
+
+ // Write the CONTINUE block header
+ if (!empty($this->_block_sizes)) {
+ $record = 0x003C;
+ $length = array_pop($this->_block_sizes);
+ $header = pack('vv', $record, $length);
+ if ($continue) {
+ $header .= pack('C', $encoding);
+ }
+ $this->_append($header);
+ }
+
+ // If the string (or substr) is small enough we can write it in the
+ // new CONTINUE block. Else, go through the loop again to write it in
+ // one or more CONTINUE blocks
+ //
+ if ($block_length < $continue_limit) {
+ $this->_append($string);
+ $written = $block_length;
+ } else {
+ $written = 0;
+ }
+ }
+ }
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/ExcelWriter/Worksheet.php b/vendor/library/Excel/phpxls/ExcelWriter/Worksheet.php
new file mode 100644
index 0000000..7f4c801
--- /dev/null
+++ b/vendor/library/Excel/phpxls/ExcelWriter/Worksheet.php
@@ -0,0 +1,3502 @@
+
+*
+* The majority of this is _NOT_ my code. I simply ported it from the
+* PERL Spreadsheet::WriteExcel module.
+*
+* The author of the Spreadsheet::WriteExcel module is John McNamara
+*
+*
+* I _DO_ maintain this code, and John McNamara has nothing to do with the
+* porting of this code to PHP. Any questions directly related to this
+* class library should be directed to me.
+*
+* License Information:
+*
+* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
+* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+require_once 'ExcelWriter/Parser.php';
+require_once 'ExcelWriter/BIFFwriter.php';
+
+/**
+* Class for generating Excel Spreadsheets
+*
+* @author Xavier Noguer
+* @category FileFormats
+* @package Spreadsheet_Excel_Writer
+*/
+
+class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwriter
+{
+ /**
+ * Name of the Worksheet
+ * @var string
+ */
+ var $name;
+
+ /**
+ * Index for the Worksheet
+ * @var integer
+ */
+ var $index;
+
+ /**
+ * Reference to the (default) Format object for URLs
+ * @var object Format
+ */
+ var $_url_format;
+
+ /**
+ * Reference to the parser used for parsing formulas
+ * @var object Format
+ */
+ var $_parser;
+
+ /**
+ * Filehandle to the temporary file for storing data
+ * @var resource
+ */
+ var $_filehandle;
+
+ /**
+ * Boolean indicating if we are using a temporary file for storing data
+ * @var bool
+ */
+ var $_using_tmpfile;
+
+ /**
+ * Maximum number of rows for an Excel spreadsheet (BIFF5)
+ * @var integer
+ */
+ var $_xls_rowmax;
+
+ /**
+ * Maximum number of columns for an Excel spreadsheet (BIFF5)
+ * @var integer
+ */
+ var $_xls_colmax;
+
+ /**
+ * Maximum number of characters for a string (LABEL record in BIFF5)
+ * @var integer
+ */
+ var $_xls_strmax;
+
+ /**
+ * First row for the DIMENSIONS record
+ * @var integer
+ * @see _storeDimensions()
+ */
+ var $_dim_rowmin;
+
+ /**
+ * Last row for the DIMENSIONS record
+ * @var integer
+ * @see _storeDimensions()
+ */
+ var $_dim_rowmax;
+
+ /**
+ * First column for the DIMENSIONS record
+ * @var integer
+ * @see _storeDimensions()
+ */
+ var $_dim_colmin;
+
+ /**
+ * Last column for the DIMENSIONS record
+ * @var integer
+ * @see _storeDimensions()
+ */
+ var $_dim_colmax;
+
+ /**
+ * Array containing format information for columns
+ * @var array
+ */
+ var $_colinfo;
+
+ /**
+ * Array containing the selected area for the worksheet
+ * @var array
+ */
+ var $_selection;
+
+ /**
+ * Array containing the panes for the worksheet
+ * @var array
+ */
+ var $_panes;
+
+ /**
+ * The active pane for the worksheet
+ * @var integer
+ */
+ var $_active_pane;
+
+ /**
+ * Bit specifying if panes are frozen
+ * @var integer
+ */
+ var $_frozen;
+
+ /**
+ * Bit specifying if the worksheet is selected
+ * @var integer
+ */
+ var $selected;
+
+ /**
+ * The paper size (for printing) (DOCUMENT!!!)
+ * @var integer
+ */
+ var $_paper_size;
+
+ /**
+ * Bit specifying paper orientation (for printing). 0 => landscape, 1 => portrait
+ * @var integer
+ */
+ var $_orientation;
+
+ /**
+ * The page header caption
+ * @var string
+ */
+ var $_header;
+
+ /**
+ * The page footer caption
+ * @var string
+ */
+ var $_footer;
+
+ /**
+ * The horizontal centering value for the page
+ * @var integer
+ */
+ var $_hcenter;
+
+ /**
+ * The vertical centering value for the page
+ * @var integer
+ */
+ var $_vcenter;
+
+ /**
+ * The margin for the header
+ * @var float
+ */
+ var $_margin_head;
+
+ /**
+ * The margin for the footer
+ * @var float
+ */
+ var $_margin_foot;
+
+ /**
+ * The left margin for the worksheet in inches
+ * @var float
+ */
+ var $_margin_left;
+
+ /**
+ * The right margin for the worksheet in inches
+ * @var float
+ */
+ var $_margin_right;
+
+ /**
+ * The top margin for the worksheet in inches
+ * @var float
+ */
+ var $_margin_top;
+
+ /**
+ * The bottom margin for the worksheet in inches
+ * @var float
+ */
+ var $_margin_bottom;
+
+ /**
+ * First row to reapeat on each printed page
+ * @var integer
+ */
+ var $title_rowmin;
+
+ /**
+ * Last row to reapeat on each printed page
+ * @var integer
+ */
+ var $title_rowmax;
+
+ /**
+ * First column to reapeat on each printed page
+ * @var integer
+ */
+ var $title_colmin;
+
+ /**
+ * First row of the area to print
+ * @var integer
+ */
+ var $print_rowmin;
+
+ /**
+ * Last row to of the area to print
+ * @var integer
+ */
+ var $print_rowmax;
+
+ /**
+ * First column of the area to print
+ * @var integer
+ */
+ var $print_colmin;
+
+ /**
+ * Last column of the area to print
+ * @var integer
+ */
+ var $print_colmax;
+
+ /**
+ * Whether to use outline.
+ * @var integer
+ */
+ var $_outline_on;
+
+ /**
+ * Auto outline styles.
+ * @var bool
+ */
+ var $_outline_style;
+
+ /**
+ * Whether to have outline summary below.
+ * @var bool
+ */
+ var $_outline_below;
+
+ /**
+ * Whether to have outline summary at the right.
+ * @var bool
+ */
+ var $_outline_right;
+
+ /**
+ * Outline row level.
+ * @var integer
+ */
+ var $_outline_row_level;
+
+ /**
+ * Whether to fit to page when printing or not.
+ * @var bool
+ */
+ var $_fit_page;
+
+ /**
+ * Number of pages to fit wide
+ * @var integer
+ */
+ var $_fit_width;
+
+ /**
+ * Number of pages to fit high
+ * @var integer
+ */
+ var $_fit_height;
+
+ /**
+ * Reference to the total number of strings in the workbook
+ * @var integer
+ */
+ var $_str_total;
+
+ /**
+ * Reference to the number of unique strings in the workbook
+ * @var integer
+ */
+ var $_str_unique;
+
+ /**
+ * Reference to the array containing all the unique strings in the workbook
+ * @var array
+ */
+ var $_str_table;
+
+ /**
+ * Merged cell ranges
+ * @var array
+ */
+ var $_merged_ranges;
+
+ /**
+ * Charset encoding currently used when calling writeString()
+ * @var string
+ */
+ var $_input_encoding;
+
+ /**
+ * Constructor
+ *
+ * @param string $name The name of the new worksheet
+ * @param integer $index The index of the new worksheet
+ * @param mixed &$activesheet The current activesheet of the workbook we belong to
+ * @param mixed &$firstsheet The first worksheet in the workbook we belong to
+ * @param mixed &$url_format The default format for hyperlinks
+ * @param mixed &$parser The formula parser created for the Workbook
+ * @access private
+ */
+ function __construct($BIFF_version, $name,
+ $index, &$activesheet,
+ &$firstsheet, &$str_total,
+ &$str_unique, &$str_table,
+ &$url_format, &$parser)
+ {
+ // It needs to call its parent's constructor explicitly
+ $this->Spreadsheet_Excel_Writer_BIFFwriter();
+ $this->_BIFF_version = $BIFF_version;
+ $rowmax = 65536; // 16384 in Excel 5
+ $colmax = 256;
+
+ $this->name = $name;
+ $this->index = $index;
+ $this->activesheet = &$activesheet;
+ $this->firstsheet = &$firstsheet;
+ $this->_str_total = &$str_total;
+ $this->_str_unique = &$str_unique;
+ $this->_str_table = &$str_table;
+ $this->_url_format = &$url_format;
+ $this->_parser = &$parser;
+
+ //$this->ext_sheets = array();
+ $this->_filehandle = '';
+ $this->_using_tmpfile = true;
+ //$this->fileclosed = 0;
+ //$this->offset = 0;
+ $this->_xls_rowmax = $rowmax;
+ $this->_xls_colmax = $colmax;
+ $this->_xls_strmax = 255;
+ $this->_dim_rowmin = $rowmax + 1;
+ $this->_dim_rowmax = 0;
+ $this->_dim_colmin = $colmax + 1;
+ $this->_dim_colmax = 0;
+ $this->_colinfo = array();
+ $this->_selection = array(0,0,0,0);
+ $this->_panes = array();
+ $this->_active_pane = 3;
+ $this->_frozen = 0;
+ $this->selected = 0;
+
+ $this->_paper_size = 0x0;
+ $this->_orientation = 0x1;
+ $this->_header = '';
+ $this->_footer = '';
+ $this->_hcenter = 0;
+ $this->_vcenter = 0;
+ $this->_margin_head = 0.50;
+ $this->_margin_foot = 0.50;
+ $this->_margin_left = 0.75;
+ $this->_margin_right = 0.75;
+ $this->_margin_top = 1.00;
+ $this->_margin_bottom = 1.00;
+
+ $this->title_rowmin = null;
+ $this->title_rowmax = null;
+ $this->title_colmin = null;
+ $this->title_colmax = null;
+ $this->print_rowmin = null;
+ $this->print_rowmax = null;
+ $this->print_colmin = null;
+ $this->print_colmax = null;
+
+ $this->_print_gridlines = 1;
+ $this->_screen_gridlines = 1;
+ $this->_print_headers = 0;
+
+ $this->_fit_page = 0;
+ $this->_fit_width = 0;
+ $this->_fit_height = 0;
+
+ $this->_hbreaks = array();
+ $this->_vbreaks = array();
+
+ $this->_protect = 0;
+ $this->_password = null;
+
+ $this->col_sizes = array();
+ $this->_row_sizes = array();
+
+ $this->_zoom = 100;
+ $this->_print_scale = 100;
+
+ $this->_outline_row_level = 0;
+ $this->_outline_style = 0;
+ $this->_outline_below = 1;
+ $this->_outline_right = 1;
+ $this->_outline_on = 1;
+
+ $this->_merged_ranges = array();
+
+ $this->_input_encoding = '';
+
+ $this->_dv = array();
+
+ $this->_initialize();
+ }
+
+ /**
+ * Open a tmp file to store the majority of the Worksheet data. If this fails,
+ * for example due to write permissions, store the data in memory. This can be
+ * slow for large files.
+ *
+ * @access private
+ */
+ function _initialize()
+ {
+ // Open tmp file for storing Worksheet data
+ $fh = tmpfile();
+ if ($fh) {
+ // Store filehandle
+ $this->_filehandle = $fh;
+ } else {
+ // If tmpfile() fails store data in memory
+ $this->_using_tmpfile = false;
+ }
+ }
+
+ /**
+ * Add data to the beginning of the workbook (note the reverse order)
+ * and to the end of the workbook.
+ *
+ * @access public
+ * @see Spreadsheet_Excel_Writer_Workbook::storeWorkbook()
+ * @param array $sheetnames The array of sheetnames from the Workbook this
+ * worksheet belongs to
+ */
+ function close($sheetnames)
+ {
+ $num_sheets = count($sheetnames);
+
+ /***********************************************
+ * Prepend in reverse order!!
+ */
+
+ // Prepend the sheet dimensions
+ $this->_storeDimensions();
+
+ // Prepend the sheet password
+ $this->_storePassword();
+
+ // Prepend the sheet protection
+ $this->_storeProtect();
+
+ // Prepend the page setup
+ $this->_storeSetup();
+
+ /* FIXME: margins are actually appended */
+ // Prepend the bottom margin
+ $this->_storeMarginBottom();
+
+ // Prepend the top margin
+ $this->_storeMarginTop();
+
+ // Prepend the right margin
+ $this->_storeMarginRight();
+
+ // Prepend the left margin
+ $this->_storeMarginLeft();
+
+ // Prepend the page vertical centering
+ $this->_storeVcenter();
+
+ // Prepend the page horizontal centering
+ $this->_storeHcenter();
+
+ // Prepend the page footer
+ $this->_storeFooter();
+
+ // Prepend the page header
+ $this->_storeHeader();
+
+ // Prepend the vertical page breaks
+ $this->_storeVbreak();
+
+ // Prepend the horizontal page breaks
+ $this->_storeHbreak();
+
+ // Prepend WSBOOL
+ $this->_storeWsbool();
+
+ // Prepend GRIDSET
+ $this->_storeGridset();
+
+ // Prepend GUTS
+ if ($this->_BIFF_version == 0x0500) {
+ $this->_storeGuts();
+ }
+
+ // Prepend PRINTGRIDLINES
+ $this->_storePrintGridlines();
+
+ // Prepend PRINTHEADERS
+ $this->_storePrintHeaders();
+
+ // Prepend EXTERNSHEET references
+ if ($this->_BIFF_version == 0x0500) {
+ for ($i = $num_sheets; $i > 0; $i--) {
+ $sheetname = $sheetnames[$i-1];
+ $this->_storeExternsheet($sheetname);
+ }
+ }
+
+ // Prepend the EXTERNCOUNT of external references.
+ if ($this->_BIFF_version == 0x0500) {
+ $this->_storeExterncount($num_sheets);
+ }
+
+ // Prepend the COLINFO records if they exist
+ if (!empty($this->_colinfo)) {
+ $colcount = count($this->_colinfo);
+ for ($i = 0; $i < $colcount; $i++) {
+ $this->_storeColinfo($this->_colinfo[$i]);
+ }
+ $this->_storeDefcol();
+ }
+
+ // Prepend the BOF record
+ $this->_storeBof(0x0010);
+
+ /*
+ * End of prepend. Read upwards from here.
+ ***********************************************/
+
+ // Append
+ $this->_storeWindow2();
+ $this->_storeZoom();
+ if (!empty($this->_panes)) {
+ $this->_storePanes($this->_panes);
+ }
+ $this->_storeSelection($this->_selection);
+ $this->_storeMergedCells();
+ /* TODO: add data validity */
+ /*if ($this->_BIFF_version == 0x0600) {
+ $this->_storeDataValidity();
+ }*/
+ $this->_storeEof();
+ }
+
+ /**
+ * Retrieve the worksheet name.
+ * This is usefull when creating worksheets without a name.
+ *
+ * @access public
+ * @return string The worksheet's name
+ */
+ function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Retrieves data from memory in one chunk, or from disk in $buffer
+ * sized chunks.
+ *
+ * @return string The data
+ */
+ function getData()
+ {
+ $buffer = 4096;
+
+ // Return data stored in memory
+ if (isset($this->_data)) {
+ $tmp = $this->_data;
+ unset($this->_data);
+ $fh = $this->_filehandle;
+ if ($this->_using_tmpfile) {
+ fseek($fh, 0);
+ }
+ return $tmp;
+ }
+ // Return data stored on disk
+ if ($this->_using_tmpfile) {
+ if ($tmp = fread($this->_filehandle, $buffer)) {
+ return $tmp;
+ }
+ }
+
+ // No data to return
+ return '';
+ }
+
+ /**
+ * Sets a merged cell range
+ *
+ * @access public
+ * @param integer $first_row First row of the area to merge
+ * @param integer $first_col First column of the area to merge
+ * @param integer $last_row Last row of the area to merge
+ * @param integer $last_col Last column of the area to merge
+ */
+ function setMerge($first_row, $first_col, $last_row, $last_col)
+ {
+ if (($last_row < $first_row) || ($last_col < $first_col)) {
+ return;
+ }
+ // don't check rowmin, rowmax, etc... because we don't know when this
+ // is going to be called
+ $this->_merged_ranges[] = array($first_row, $first_col, $last_row, $last_col);
+ }
+
+ /**
+ * Set this worksheet as a selected worksheet,
+ * i.e. the worksheet has its tab highlighted.
+ *
+ * @access public
+ */
+ function select()
+ {
+ $this->selected = 1;
+ }
+
+ /**
+ * Set this worksheet as the active worksheet,
+ * i.e. the worksheet that is displayed when the workbook is opened.
+ * Also set it as selected.
+ *
+ * @access public
+ */
+ function activate()
+ {
+ $this->selected = 1;
+ $this->activesheet = $this->index;
+ }
+
+ /**
+ * Set this worksheet as the first visible sheet.
+ * This is necessary when there are a large number of worksheets and the
+ * activated worksheet is not visible on the screen.
+ *
+ * @access public
+ */
+ function setFirstSheet()
+ {
+ $this->firstsheet = $this->index;
+ }
+
+ /**
+ * Set the worksheet protection flag
+ * to prevent accidental modification and to
+ * hide formulas if the locked and hidden format properties have been set.
+ *
+ * @access public
+ * @param string $password The password to use for protecting the sheet.
+ */
+ function protect($password)
+ {
+ $this->_protect = 1;
+ $this->_password = $this->_encodePassword($password);
+ }
+
+ /**
+ * Set the width of a single column or a range of columns.
+ *
+ * @access public
+ * @param integer $firstcol first column on the range
+ * @param integer $lastcol last column on the range
+ * @param integer $width width to set
+ * @param mixed $format The optional XF format to apply to the columns
+ * @param integer $hidden The optional hidden atribute
+ * @param integer $level The optional outline level
+ */
+ function setColumn($firstcol, $lastcol, $width, $format = null, $hidden = 0, $level = 0)
+ {
+ $this->_colinfo[] = array($firstcol, $lastcol, $width, &$format, $hidden, $level);
+
+ // Set width to zero if column is hidden
+ $width = ($hidden) ? 0 : $width;
+
+ for ($col = $firstcol; $col <= $lastcol; $col++) {
+ $this->col_sizes[$col] = $width;
+ }
+ }
+
+ /**
+ * Set which cell or cells are selected in a worksheet
+ *
+ * @access public
+ * @param integer $first_row first row in the selected quadrant
+ * @param integer $first_column first column in the selected quadrant
+ * @param integer $last_row last row in the selected quadrant
+ * @param integer $last_column last column in the selected quadrant
+ */
+ function setSelection($first_row,$first_column,$last_row,$last_column)
+ {
+ $this->_selection = array($first_row,$first_column,$last_row,$last_column);
+ }
+
+ /**
+ * Set panes and mark them as frozen.
+ *
+ * @access public
+ * @param array $panes This is the only parameter received and is composed of the following:
+ * 0 => Vertical split position,
+ * 1 => Horizontal split position
+ * 2 => Top row visible
+ * 3 => Leftmost column visible
+ * 4 => Active pane
+ */
+ function freezePanes($panes)
+ {
+ $this->_frozen = 1;
+ $this->_panes = $panes;
+ }
+
+ /**
+ * Set panes and mark them as unfrozen.
+ *
+ * @access public
+ * @param array $panes This is the only parameter received and is composed of the following:
+ * 0 => Vertical split position,
+ * 1 => Horizontal split position
+ * 2 => Top row visible
+ * 3 => Leftmost column visible
+ * 4 => Active pane
+ */
+ function thawPanes($panes)
+ {
+ $this->_frozen = 0;
+ $this->_panes = $panes;
+ }
+
+ /**
+ * Set the page orientation as portrait.
+ *
+ * @access public
+ */
+ function setPortrait()
+ {
+ $this->_orientation = 1;
+ }
+
+ /**
+ * Set the page orientation as landscape.
+ *
+ * @access public
+ */
+ function setLandscape()
+ {
+ $this->_orientation = 0;
+ }
+
+ /**
+ * Set the paper type. Ex. 1 = US Letter, 9 = A4
+ *
+ * @access public
+ * @param integer $size The type of paper size to use
+ */
+ function setPaper($size = 0)
+ {
+ $this->_paper_size = $size;
+ }
+
+
+ /**
+ * Set the page header caption and optional margin.
+ *
+ * @access public
+ * @param string $string The header text
+ * @param float $margin optional head margin in inches.
+ */
+ function setHeader($string,$margin = 0.50)
+ {
+ if (strlen($string) >= 255) {
+ //carp 'Header string must be less than 255 characters';
+ return;
+ }
+ $this->_header = $string;
+ $this->_margin_head = $margin;
+ }
+
+ /**
+ * Set the page footer caption and optional margin.
+ *
+ * @access public
+ * @param string $string The footer text
+ * @param float $margin optional foot margin in inches.
+ */
+ function setFooter($string,$margin = 0.50)
+ {
+ if (strlen($string) >= 255) {
+ //carp 'Footer string must be less than 255 characters';
+ return;
+ }
+ $this->_footer = $string;
+ $this->_margin_foot = $margin;
+ }
+
+ /**
+ * Center the page horinzontally.
+ *
+ * @access public
+ * @param integer $center the optional value for centering. Defaults to 1 (center).
+ */
+ function centerHorizontally($center = 1)
+ {
+ $this->_hcenter = $center;
+ }
+
+ /**
+ * Center the page vertically.
+ *
+ * @access public
+ * @param integer $center the optional value for centering. Defaults to 1 (center).
+ */
+ function centerVertically($center = 1)
+ {
+ $this->_vcenter = $center;
+ }
+
+ /**
+ * Set all the page margins to the same value in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMargins($margin)
+ {
+ $this->setMarginLeft($margin);
+ $this->setMarginRight($margin);
+ $this->setMarginTop($margin);
+ $this->setMarginBottom($margin);
+ }
+
+ /**
+ * Set the left and right margins to the same value in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMargins_LR($margin)
+ {
+ $this->setMarginLeft($margin);
+ $this->setMarginRight($margin);
+ }
+
+ /**
+ * Set the top and bottom margins to the same value in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMargins_TB($margin)
+ {
+ $this->setMarginTop($margin);
+ $this->setMarginBottom($margin);
+ }
+
+ /**
+ * Set the left margin in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMarginLeft($margin = 0.75)
+ {
+ $this->_margin_left = $margin;
+ }
+
+ /**
+ * Set the right margin in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMarginRight($margin = 0.75)
+ {
+ $this->_margin_right = $margin;
+ }
+
+ /**
+ * Set the top margin in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMarginTop($margin = 1.00)
+ {
+ $this->_margin_top = $margin;
+ }
+
+ /**
+ * Set the bottom margin in inches.
+ *
+ * @access public
+ * @param float $margin The margin to set in inches
+ */
+ function setMarginBottom($margin = 1.00)
+ {
+ $this->_margin_bottom = $margin;
+ }
+
+ /**
+ * Set the rows to repeat at the top of each printed page.
+ *
+ * @access public
+ * @param integer $first_row First row to repeat
+ * @param integer $last_row Last row to repeat. Optional.
+ */
+ function repeatRows($first_row, $last_row = null)
+ {
+ $this->title_rowmin = $first_row;
+ if (isset($last_row)) { //Second row is optional
+ $this->title_rowmax = $last_row;
+ } else {
+ $this->title_rowmax = $first_row;
+ }
+ }
+
+ /**
+ * Set the columns to repeat at the left hand side of each printed page.
+ *
+ * @access public
+ * @param integer $first_col First column to repeat
+ * @param integer $last_col Last column to repeat. Optional.
+ */
+ function repeatColumns($first_col, $last_col = null)
+ {
+ $this->title_colmin = $first_col;
+ if (isset($last_col)) { // Second col is optional
+ $this->title_colmax = $last_col;
+ } else {
+ $this->title_colmax = $first_col;
+ }
+ }
+
+ /**
+ * Set the area of each worksheet that will be printed.
+ *
+ * @access public
+ * @param integer $first_row First row of the area to print
+ * @param integer $first_col First column of the area to print
+ * @param integer $last_row Last row of the area to print
+ * @param integer $last_col Last column of the area to print
+ */
+ function printArea($first_row, $first_col, $last_row, $last_col)
+ {
+ $this->print_rowmin = $first_row;
+ $this->print_colmin = $first_col;
+ $this->print_rowmax = $last_row;
+ $this->print_colmax = $last_col;
+ }
+
+
+ /**
+ * Set the option to hide gridlines on the printed page.
+ *
+ * @access public
+ */
+ function hideGridlines()
+ {
+ $this->_print_gridlines = 0;
+ }
+
+ /**
+ * Set the option to hide gridlines on the worksheet (as seen on the screen).
+ *
+ * @access public
+ */
+ function hideScreenGridlines()
+ {
+ $this->_screen_gridlines = 0;
+ }
+
+ /**
+ * Set the option to print the row and column headers on the printed page.
+ *
+ * @access public
+ * @param integer $print Whether to print the headers or not. Defaults to 1 (print).
+ */
+ function printRowColHeaders($print = 1)
+ {
+ $this->_print_headers = $print;
+ }
+
+ /**
+ * Set the vertical and horizontal number of pages that will define the maximum area printed.
+ * It doesn't seem to work with OpenOffice.
+ *
+ * @access public
+ * @param integer $width Maximun width of printed area in pages
+ * @param integer $height Maximun heigth of printed area in pages
+ * @see setPrintScale()
+ */
+ function fitToPages($width, $height)
+ {
+ $this->_fit_page = 1;
+ $this->_fit_width = $width;
+ $this->_fit_height = $height;
+ }
+
+ /**
+ * Store the horizontal page breaks on a worksheet (for printing).
+ * The breaks represent the row after which the break is inserted.
+ *
+ * @access public
+ * @param array $breaks Array containing the horizontal page breaks
+ */
+ function setHPagebreaks($breaks)
+ {
+ foreach ($breaks as $break) {
+ array_push($this->_hbreaks, $break);
+ }
+ }
+
+ /**
+ * Store the vertical page breaks on a worksheet (for printing).
+ * The breaks represent the column after which the break is inserted.
+ *
+ * @access public
+ * @param array $breaks Array containing the vertical page breaks
+ */
+ function setVPagebreaks($breaks)
+ {
+ foreach ($breaks as $break) {
+ array_push($this->_vbreaks, $break);
+ }
+ }
+
+
+ /**
+ * Set the worksheet zoom factor.
+ *
+ * @access public
+ * @param integer $scale The zoom factor
+ */
+ function setZoom($scale = 100)
+ {
+ // Confine the scale to Excel's range
+ if ($scale < 10 || $scale > 400) {
+ $this->raiseError("Zoom factor $scale outside range: 10 <= zoom <= 400");
+ $scale = 100;
+ }
+
+ $this->_zoom = floor($scale);
+ }
+
+ /**
+ * Set the scale factor for the printed page.
+ * It turns off the "fit to page" option
+ *
+ * @access public
+ * @param integer $scale The optional scale factor. Defaults to 100
+ */
+ function setPrintScale($scale = 100)
+ {
+ // Confine the scale to Excel's range
+ if ($scale < 10 || $scale > 400) {
+ $this->raiseError("Print scale $scale outside range: 10 <= zoom <= 400");
+ $scale = 100;
+ }
+
+ // Turn off "fit to page" option
+ $this->_fit_page = 0;
+
+ $this->_print_scale = floor($scale);
+ }
+
+ /**
+ * Map to the appropriate write method acording to the token recieved.
+ *
+ * @access public
+ * @param integer $row The row of the cell we are writing to
+ * @param integer $col The column of the cell we are writing to
+ * @param mixed $token What we are writing
+ * @param mixed $format The optional format to apply to the cell
+ */
+ function write($row, $col, $token, $format = null)
+ {
+ // Check for a cell reference in A1 notation and substitute row and column
+ /*if ($_[0] =~ /^\D/) {
+ @_ = $this->_substituteCellref(@_);
+ }*/
+
+ if (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/", $token)) {
+ // Match number
+ return $this->writeNumber($row, $col, $token, $format);
+ } elseif (preg_match("/^[fh]tt?p:\/\//", $token)) {
+ // Match http or ftp URL
+ return $this->writeUrl($row, $col, $token, '', $format);
+ } elseif (preg_match("/^mailto:/", $token)) {
+ // Match mailto:
+ return $this->writeUrl($row, $col, $token, '', $format);
+ } elseif (preg_match("/^(?:in|ex)ternal:/", $token)) {
+ // Match internal or external sheet link
+ return $this->writeUrl($row, $col, $token, '', $format);
+ } elseif (preg_match("/^=/", $token)) {
+ // Match formula
+ return $this->writeFormula($row, $col, $token, $format);
+ } elseif (preg_match("/^@/", $token)) {
+ // Match formula
+ return $this->writeFormula($row, $col, $token, $format);
+ } elseif ($token == '') {
+ // Match blank
+ return $this->writeBlank($row, $col, $format);
+ } else {
+ // Default: match string
+ return $this->writeString($row, $col, $token, $format);
+ }
+ }
+
+ /**
+ * Write an array of values as a row
+ *
+ * @access public
+ * @param integer $row The row we are writing to
+ * @param integer $col The first col (leftmost col) we are writing to
+ * @param array $val The array of values to write
+ * @param mixed $format The optional format to apply to the cell
+ * @return mixed PEAR_Error on failure
+ */
+
+ function writeRow($row, $col, $val, $format = null)
+ {
+ $retval = '';
+ if (is_array($val)) {
+ foreach ($val as $v) {
+ if (is_array($v)) {
+ $this->writeCol($row, $col, $v, $format);
+ } else {
+ $this->write($row, $col, $v, $format);
+ }
+ $col++;
+ }
+ } else {
+ $retval = new PEAR_Error('$val needs to be an array');
+ }
+ return($retval);
+ }
+
+ /**
+ * Write an array of values as a column
+ *
+ * @access public
+ * @param integer $row The first row (uppermost row) we are writing to
+ * @param integer $col The col we are writing to
+ * @param array $val The array of values to write
+ * @param mixed $format The optional format to apply to the cell
+ * @return mixed PEAR_Error on failure
+ */
+
+ function writeCol($row, $col, $val, $format = null)
+ {
+ $retval = '';
+ if (is_array($val)) {
+ foreach ($val as $v) {
+ $this->write($row, $col, $v, $format);
+ $row++;
+ }
+ } else {
+ $retval = new PEAR_Error('$val needs to be an array');
+ }
+ return($retval);
+ }
+
+ /**
+ * Returns an index to the XF record in the workbook
+ *
+ * @access private
+ * @param mixed &$format The optional XF format
+ * @return integer The XF record index
+ */
+ function _XF(&$format)
+ {
+ if ($format) {
+ return($format->getXfIndex());
+ } else {
+ return(0x0F);
+ }
+ }
+
+
+ /******************************************************************************
+ *******************************************************************************
+ *
+ * Internal methods
+ */
+
+
+ /**
+ * Store Worksheet data in memory using the parent's class append() or to a
+ * temporary file, the default.
+ *
+ * @access private
+ * @param string $data The binary data to append
+ */
+ function _append($data)
+ {
+ if ($this->_using_tmpfile) {
+ // Add CONTINUE records if necessary
+ if (strlen($data) > $this->_limit) {
+ $data = $this->_addContinue($data);
+ }
+ fwrite($this->_filehandle, $data);
+ $this->_datasize += strlen($data);
+ } else {
+ parent::_append($data);
+ }
+ }
+
+ /**
+ * Substitute an Excel cell reference in A1 notation for zero based row and
+ * column values in an argument list.
+ *
+ * Ex: ("A4", "Hello") is converted to (3, 0, "Hello").
+ *
+ * @access private
+ * @param string $cell The cell reference. Or range of cells.
+ * @return array
+ */
+ function _substituteCellref($cell)
+ {
+ $cell = strtoupper($cell);
+
+ // Convert a column range: 'A:A' or 'B:G'
+ if (preg_match("/([A-I]?[A-Z]):([A-I]?[A-Z])/", $cell, $match)) {
+ list($no_use, $col1) = $this->_cellToRowcol($match[1] .'1'); // Add a dummy row
+ list($no_use, $col2) = $this->_cellToRowcol($match[2] .'1'); // Add a dummy row
+ return(array($col1, $col2));
+ }
+
+ // Convert a cell range: 'A1:B7'
+ if (preg_match("/\$?([A-I]?[A-Z]\$?\d+):\$?([A-I]?[A-Z]\$?\d+)/", $cell, $match)) {
+ list($row1, $col1) = $this->_cellToRowcol($match[1]);
+ list($row2, $col2) = $this->_cellToRowcol($match[2]);
+ return(array($row1, $col1, $row2, $col2));
+ }
+
+ // Convert a cell reference: 'A1' or 'AD2000'
+ if (preg_match("/\$?([A-I]?[A-Z]\$?\d+)/", $cell)) {
+ list($row1, $col1) = $this->_cellToRowcol($match[1]);
+ return(array($row1, $col1));
+ }
+
+ // TODO use real error codes
+ $this->raiseError("Unknown cell reference $cell", 0, PEAR_ERROR_DIE);
+ }
+
+ /**
+ * Convert an Excel cell reference in A1 notation to a zero based row and column
+ * reference; converts C1 to (0, 2).
+ *
+ * @access private
+ * @param string $cell The cell reference.
+ * @return array containing (row, column)
+ */
+ function _cellToRowcol($cell)
+ {
+ preg_match("/\$?([A-I]?[A-Z])\$?(\d+)/",$cell,$match);
+ $col = $match[1];
+ $row = $match[2];
+
+ // Convert base26 column string to number
+ $chars = split('', $col);
+ $expn = 0;
+ $col = 0;
+
+ while ($chars) {
+ $char = array_pop($chars); // LS char first
+ $col += (ord($char) -ord('A') +1) * pow(26,$expn);
+ $expn++;
+ }
+
+ // Convert 1-index to zero-index
+ $row--;
+ $col--;
+
+ return(array($row, $col));
+ }
+
+ /**
+ * Based on the algorithm provided by Daniel Rentz of OpenOffice.
+ *
+ * @access private
+ * @param string $plaintext The password to be encoded in plaintext.
+ * @return string The encoded password
+ */
+ function _encodePassword($plaintext)
+ {
+ $password = 0x0000;
+ $i = 1; // char position
+
+ // split the plain text password in its component characters
+ $chars = preg_split('//', $plaintext, -1, PREG_SPLIT_NO_EMPTY);
+ foreach ($chars as $char) {
+ $value = ord($char) << $i; // shifted ASCII value
+ $rotated_bits = $value >> 15; // rotated bits beyond bit 15
+ $value &= 0x7fff; // first 15 bits
+ $password ^= ($value | $rotated_bits);
+ $i++;
+ }
+
+ $password ^= strlen($plaintext);
+ $password ^= 0xCE4B;
+
+ return($password);
+ }
+
+ /**
+ * This method sets the properties for outlining and grouping. The defaults
+ * correspond to Excel's defaults.
+ *
+ * @param bool $visible
+ * @param bool $symbols_below
+ * @param bool $symbols_right
+ * @param bool $auto_style
+ */
+ function setOutline($visible = true, $symbols_below = true, $symbols_right = true, $auto_style = false)
+ {
+ $this->_outline_on = $visible;
+ $this->_outline_below = $symbols_below;
+ $this->_outline_right = $symbols_right;
+ $this->_outline_style = $auto_style;
+
+ // Ensure this is a boolean vale for Window2
+ if ($this->_outline_on) {
+ $this->_outline_on = 1;
+ }
+ }
+
+ /******************************************************************************
+ *******************************************************************************
+ *
+ * BIFF RECORDS
+ */
+
+
+ /**
+ * Write a double to the specified row and column (zero indexed).
+ * An integer can be written as a double. Excel will display an
+ * integer. $format is optional.
+ *
+ * Returns 0 : normal termination
+ * -2 : row or column out of range
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param float $num The number to write
+ * @param mixed $format The optional XF format
+ * @return integer
+ */
+ function writeNumber($row, $col, $num, $format = null)
+ {
+ $record = 0x0203; // Record identifier
+ $length = 0x000E; // Number of bytes to follow
+
+ $xf = $this->_XF($format); // The cell format
+
+ // Check that row and col are valid and store max and min values
+ if ($row >= $this->_xls_rowmax) {
+ return(-2);
+ }
+ if ($col >= $this->_xls_colmax) {
+ return(-2);
+ }
+ if ($row < $this->_dim_rowmin) {
+ $this->_dim_rowmin = $row;
+ }
+ if ($row > $this->_dim_rowmax) {
+ $this->_dim_rowmax = $row;
+ }
+ if ($col < $this->_dim_colmin) {
+ $this->_dim_colmin = $col;
+ }
+ if ($col > $this->_dim_colmax) {
+ $this->_dim_colmax = $col;
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvv", $row, $col, $xf);
+ $xl_double = pack("d", $num);
+ if ($this->_byte_order) { // if it's Big Endian
+ $xl_double = strrev($xl_double);
+ }
+
+ $this->_append($header.$data.$xl_double);
+ return(0);
+ }
+
+ /**
+ * Write a string to the specified row and column (zero indexed).
+ * NOTE: there is an Excel 5 defined limit of 255 characters.
+ * $format is optional.
+ * Returns 0 : normal termination
+ * -2 : row or column out of range
+ * -3 : long string truncated to 255 chars
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param string $str The string to write
+ * @param mixed $format The XF format for the cell
+ * @return integer
+ */
+ function writeString($row, $col, $str, $format = null)
+ {
+ if ($this->_BIFF_version == 0x0600) {
+ return $this->writeStringBIFF8($row, $col, $str, $format);
+ }
+ $strlen = strlen($str);
+ $record = 0x0204; // Record identifier
+ $length = 0x0008 + $strlen; // Bytes to follow
+ $xf = $this->_XF($format); // The cell format
+
+ $str_error = 0;
+
+ // Check that row and col are valid and store max and min values
+ if ($row >= $this->_xls_rowmax) {
+ return(-2);
+ }
+ if ($col >= $this->_xls_colmax) {
+ return(-2);
+ }
+ if ($row < $this->_dim_rowmin) {
+ $this->_dim_rowmin = $row;
+ }
+ if ($row > $this->_dim_rowmax) {
+ $this->_dim_rowmax = $row;
+ }
+ if ($col < $this->_dim_colmin) {
+ $this->_dim_colmin = $col;
+ }
+ if ($col > $this->_dim_colmax) {
+ $this->_dim_colmax = $col;
+ }
+
+ if ($strlen > $this->_xls_strmax) { // LABEL must be < 255 chars
+ $str = substr($str, 0, $this->_xls_strmax);
+ $length = 0x0008 + $this->_xls_strmax;
+ $strlen = $this->_xls_strmax;
+ $str_error = -3;
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvv", $row, $col, $xf, $strlen);
+ $this->_append($header . $data . $str);
+ return($str_error);
+ }
+
+ /**
+ * Sets Input Encoding for writing strings
+ *
+ * @access public
+ * @param string $encoding The encoding. Ex: 'UTF-16LE', 'utf-8', 'ISO-859-7'
+ */
+ function setInputEncoding($encoding)
+ {
+ if ($encoding != 'UTF-16LE' && !function_exists('iconv')) {
+ $this->raiseError("Using an input encoding other than UTF-16LE requires PHP support for iconv");
+ }
+ $this->_input_encoding = $encoding;
+ }
+
+ /**
+ * Write a string to the specified row and column (zero indexed).
+ * This is the BIFF8 version (no 255 chars limit).
+ * $format is optional.
+ * Returns 0 : normal termination
+ * -2 : row or column out of range
+ * -3 : long string truncated to 255 chars
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param string $str The string to write
+ * @param mixed $format The XF format for the cell
+ * @return integer
+ */
+ function writeStringBIFF8($row, $col, $str, $format = null)
+ {
+ if ($this->_input_encoding == 'UTF-16LE')
+ {
+ $strlen = function_exists('mb_strlen') ? mb_strlen($str, 'UTF-16LE') : (strlen($str) / 2);
+ $encoding = 0x1;
+ }
+ elseif ($this->_input_encoding != '')
+ {
+ $str = iconv($this->_input_encoding, 'UTF-16LE', $str);
+ $strlen = function_exists('mb_strlen') ? mb_strlen($str, 'UTF-16LE') : (strlen($str) / 2);
+ $encoding = 0x1;
+ }
+ else
+ {
+ $strlen = strlen($str);
+ $encoding = 0x0;
+ }
+ $record = 0x00FD; // Record identifier
+ $length = 0x000A; // Bytes to follow
+ $xf = $this->_XF($format); // The cell format
+
+ $str_error = 0;
+
+ // Check that row and col are valid and store max and min values
+ if ($this->_checkRowCol($row, $col) == false) {
+ return -2;
+ }
+
+ $str = pack('vC', $strlen, $encoding).$str;
+
+ /* check if string is already present */
+ if (!isset($this->_str_table[$str])) {
+ $this->_str_table[$str] = $this->_str_unique++;
+ }
+ $this->_str_total++;
+
+ $header = pack('vv', $record, $length);
+ $data = pack('vvvV', $row, $col, $xf, $this->_str_table[$str]);
+ $this->_append($header.$data);
+ return $str_error;
+ }
+
+ /**
+ * Check row and col before writing to a cell, and update the sheet's
+ * dimensions accordingly
+ *
+ * @access private
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @return boolean true for success, false if row and/or col are grester
+ * then maximums allowed.
+ */
+ function _checkRowCol($row, $col)
+ {
+ if ($row >= $this->_xls_rowmax) {
+ return false;
+ }
+ if ($col >= $this->_xls_colmax) {
+ return false;
+ }
+ if ($row < $this->_dim_rowmin) {
+ $this->_dim_rowmin = $row;
+ }
+ if ($row > $this->_dim_rowmax) {
+ $this->_dim_rowmax = $row;
+ }
+ if ($col < $this->_dim_colmin) {
+ $this->_dim_colmin = $col;
+ }
+ if ($col > $this->_dim_colmax) {
+ $this->_dim_colmax = $col;
+ }
+ return true;
+ }
+
+ /**
+ * Writes a note associated with the cell given by the row and column.
+ * NOTE records don't have a length limit.
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param string $note The note to write
+ */
+ function writeNote($row, $col, $note)
+ {
+ $note_length = strlen($note);
+ $record = 0x001C; // Record identifier
+ $max_length = 2048; // Maximun length for a NOTE record
+ //$length = 0x0006 + $note_length; // Bytes to follow
+
+ // Check that row and col are valid and store max and min values
+ if ($row >= $this->_xls_rowmax) {
+ return(-2);
+ }
+ if ($col >= $this->_xls_colmax) {
+ return(-2);
+ }
+ if ($row < $this->_dim_rowmin) {
+ $this->_dim_rowmin = $row;
+ }
+ if ($row > $this->_dim_rowmax) {
+ $this->_dim_rowmax = $row;
+ }
+ if ($col < $this->_dim_colmin) {
+ $this->_dim_colmin = $col;
+ }
+ if ($col > $this->_dim_colmax) {
+ $this->_dim_colmax = $col;
+ }
+
+ // Length for this record is no more than 2048 + 6
+ $length = 0x0006 + min($note_length, 2048);
+ $header = pack("vv", $record, $length);
+ $data = pack("vvv", $row, $col, $note_length);
+ $this->_append($header . $data . substr($note, 0, 2048));
+
+ for ($i = $max_length; $i < $note_length; $i += $max_length) {
+ $chunk = substr($note, $i, $max_length);
+ $length = 0x0006 + strlen($chunk);
+ $header = pack("vv", $record, $length);
+ $data = pack("vvv", -1, 0, strlen($chunk));
+ $this->_append($header.$data.$chunk);
+ }
+ return(0);
+ }
+
+ /**
+ * Write a blank cell to the specified row and column (zero indexed).
+ * A blank cell is used to specify formatting without adding a string
+ * or a number.
+ *
+ * A blank cell without a format serves no purpose. Therefore, we don't write
+ * a BLANK record unless a format is specified.
+ *
+ * Returns 0 : normal termination (including no format)
+ * -1 : insufficient number of arguments
+ * -2 : row or column out of range
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param mixed $format The XF format
+ */
+ function writeBlank($row, $col, $format)
+ {
+ // Don't write a blank cell unless it has a format
+ if (!$format) {
+ return(0);
+ }
+
+ $record = 0x0201; // Record identifier
+ $length = 0x0006; // Number of bytes to follow
+ $xf = $this->_XF($format); // The cell format
+
+ // Check that row and col are valid and store max and min values
+ if ($row >= $this->_xls_rowmax) {
+ return(-2);
+ }
+ if ($col >= $this->_xls_colmax) {
+ return(-2);
+ }
+ if ($row < $this->_dim_rowmin) {
+ $this->_dim_rowmin = $row;
+ }
+ if ($row > $this->_dim_rowmax) {
+ $this->_dim_rowmax = $row;
+ }
+ if ($col < $this->_dim_colmin) {
+ $this->_dim_colmin = $col;
+ }
+ if ($col > $this->_dim_colmax) {
+ $this->_dim_colmax = $col;
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvv", $row, $col, $xf);
+ $this->_append($header . $data);
+ return 0;
+ }
+
+ /**
+ * Write a formula to the specified row and column (zero indexed).
+ * The textual representation of the formula is passed to the parser in
+ * Parser.php which returns a packed binary string.
+ *
+ * Returns 0 : normal termination
+ * -1 : formula errors (bad formula)
+ * -2 : row or column out of range
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param string $formula The formula text string
+ * @param mixed $format The optional XF format
+ * @return integer
+ */
+ function writeFormula($row, $col, $formula, $format = null)
+ {
+ $record = 0x0006; // Record identifier
+
+ // Excel normally stores the last calculated value of the formula in $num.
+ // Clearly we are not in a position to calculate this a priori. Instead
+ // we set $num to zero and set the option flags in $grbit to ensure
+ // automatic calculation of the formula when the file is opened.
+ //
+ $xf = $this->_XF($format); // The cell format
+ $num = 0x00; // Current value of formula
+ $grbit = 0x03; // Option flags
+ $unknown = 0x0000; // Must be zero
+
+
+ // Check that row and col are valid and store max and min values
+ if ($this->_checkRowCol($row, $col) == false) {
+ return -2;
+ }
+
+ // Strip the '=' or '@' sign at the beginning of the formula string
+ if (preg_match("/^=/", $formula)) {
+ $formula = preg_replace("/(^=)/", "", $formula);
+ } elseif (preg_match("/^@/", $formula)) {
+ $formula = preg_replace("/(^@)/", "", $formula);
+ } else {
+ // Error handling
+ $this->writeString($row, $col, 'Unrecognised character for formula');
+ return -1;
+ }
+
+ // Parse the formula using the parser in Parser.php
+ $error = $this->_parser->parse($formula);
+ if ($this->isError($error)) {
+ $this->writeString($row, $col, $error->getMessage());
+ return -1;
+ }
+
+ $formula = $this->_parser->toReversePolish();
+ if ($this->isError($formula)) {
+ $this->writeString($row, $col, $formula->getMessage());
+ return -1;
+ }
+
+ $formlen = strlen($formula); // Length of the binary string
+ $length = 0x16 + $formlen; // Length of the record data
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvdvVv", $row, $col, $xf, $num,
+ $grbit, $unknown, $formlen);
+
+ $this->_append($header . $data . $formula);
+ return 0;
+ }
+
+ /**
+ * Write a hyperlink.
+ * This is comprised of two elements: the visible label and
+ * the invisible link. The visible label is the same as the link unless an
+ * alternative string is specified. The label is written using the
+ * writeString() method. Therefore the 255 characters string limit applies.
+ * $string and $format are optional.
+ *
+ * The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external
+ * directory url.
+ *
+ * Returns 0 : normal termination
+ * -2 : row or column out of range
+ * -3 : long string truncated to 255 chars
+ *
+ * @access public
+ * @param integer $row Row
+ * @param integer $col Column
+ * @param string $url URL string
+ * @param string $string Alternative label
+ * @param mixed $format The cell format
+ * @return integer
+ */
+ function writeUrl($row, $col, $url, $string = '', $format = null)
+ {
+ // Add start row and col to arg list
+ return($this->_writeUrlRange($row, $col, $row, $col, $url, $string, $format));
+ }
+
+ /**
+ * This is the more general form of writeUrl(). It allows a hyperlink to be
+ * written to a range of cells. This function also decides the type of hyperlink
+ * to be written. These are either, Web (http, ftp, mailto), Internal
+ * (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1').
+ *
+ * @access private
+ * @see writeUrl()
+ * @param integer $row1 Start row
+ * @param integer $col1 Start column
+ * @param integer $row2 End row
+ * @param integer $col2 End column
+ * @param string $url URL string
+ * @param string $string Alternative label
+ * @param mixed $format The cell format
+ * @return integer
+ */
+
+ function _writeUrlRange($row1, $col1, $row2, $col2, $url, $string = '', $format = null)
+ {
+
+ // Check for internal/external sheet links or default to web link
+ if (preg_match('[^internal:]', $url)) {
+ return($this->_writeUrlInternal($row1, $col1, $row2, $col2, $url, $string, $format));
+ }
+ if (preg_match('[^external:]', $url)) {
+ return($this->_writeUrlExternal($row1, $col1, $row2, $col2, $url, $string, $format));
+ }
+ return($this->_writeUrlWeb($row1, $col1, $row2, $col2, $url, $string, $format));
+ }
+
+
+ /**
+ * Used to write http, ftp and mailto hyperlinks.
+ * The link type ($options) is 0x03 is the same as absolute dir ref without
+ * sheet. However it is differentiated by the $unknown2 data stream.
+ *
+ * @access private
+ * @see writeUrl()
+ * @param integer $row1 Start row
+ * @param integer $col1 Start column
+ * @param integer $row2 End row
+ * @param integer $col2 End column
+ * @param string $url URL string
+ * @param string $str Alternative label
+ * @param mixed $format The cell format
+ * @return integer
+ */
+ function _writeUrlWeb($row1, $col1, $row2, $col2, $url, $str, $format = null)
+ {
+ $record = 0x01B8; // Record identifier
+ $length = 0x00000; // Bytes to follow
+
+ if (!$format) {
+ $format = $this->_url_format;
+ }
+
+ // Write the visible label using the writeString() method.
+ if ($str == '') {
+ $str = $url;
+ }
+ $str_error = $this->writeString($row1, $col1, $str, $format);
+ if (($str_error == -2) || ($str_error == -3)) {
+ return $str_error;
+ }
+
+ // Pack the undocumented parts of the hyperlink stream
+ $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000");
+ $unknown2 = pack("H*", "E0C9EA79F9BACE118C8200AA004BA90B");
+
+ // Pack the option flags
+ $options = pack("V", 0x03);
+
+ // Convert URL to a null terminated wchar string
+ $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY));
+ $url = $url . "\0\0\0";
+
+ // Pack the length of the URL
+ $url_len = pack("V", strlen($url));
+
+ // Calculate the data length
+ $length = 0x34 + strlen($url);
+
+ // Pack the header data
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvv", $row1, $row2, $col1, $col2);
+
+ // Write the packed data
+ $this->_append($header . $data .
+ $unknown1 . $options .
+ $unknown2 . $url_len . $url);
+ return($str_error);
+ }
+
+ /**
+ * Used to write internal reference hyperlinks such as "Sheet1!A1".
+ *
+ * @access private
+ * @see writeUrl()
+ * @param integer $row1 Start row
+ * @param integer $col1 Start column
+ * @param integer $row2 End row
+ * @param integer $col2 End column
+ * @param string $url URL string
+ * @param string $str Alternative label
+ * @param mixed $format The cell format
+ * @return integer
+ */
+ function _writeUrlInternal($row1, $col1, $row2, $col2, $url, $str, $format = null)
+ {
+ $record = 0x01B8; // Record identifier
+ $length = 0x00000; // Bytes to follow
+
+ if (!$format) {
+ $format = $this->_url_format;
+ }
+
+ // Strip URL type
+ $url = preg_replace('/^internal:/', '', $url);
+
+ // Write the visible label
+ if ($str == '') {
+ $str = $url;
+ }
+ $str_error = $this->writeString($row1, $col1, $str, $format);
+ if (($str_error == -2) || ($str_error == -3)) {
+ return $str_error;
+ }
+
+ // Pack the undocumented parts of the hyperlink stream
+ $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000");
+
+ // Pack the option flags
+ $options = pack("V", 0x08);
+
+ // Convert the URL type and to a null terminated wchar string
+ $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY));
+ $url = $url . "\0\0\0";
+
+ // Pack the length of the URL as chars (not wchars)
+ $url_len = pack("V", floor(strlen($url)/2));
+
+ // Calculate the data length
+ $length = 0x24 + strlen($url);
+
+ // Pack the header data
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvv", $row1, $row2, $col1, $col2);
+
+ // Write the packed data
+ $this->_append($header . $data .
+ $unknown1 . $options .
+ $url_len . $url);
+ return($str_error);
+ }
+
+ /**
+ * Write links to external directory names such as 'c:\foo.xls',
+ * c:\foo.xls#Sheet1!A1', '../../foo.xls'. and '../../foo.xls#Sheet1!A1'.
+ *
+ * Note: Excel writes some relative links with the $dir_long string. We ignore
+ * these cases for the sake of simpler code.
+ *
+ * @access private
+ * @see writeUrl()
+ * @param integer $row1 Start row
+ * @param integer $col1 Start column
+ * @param integer $row2 End row
+ * @param integer $col2 End column
+ * @param string $url URL string
+ * @param string $str Alternative label
+ * @param mixed $format The cell format
+ * @return integer
+ */
+ function _writeUrlExternal($row1, $col1, $row2, $col2, $url, $str, $format = null)
+ {
+ // Network drives are different. We will handle them separately
+ // MS/Novell network drives and shares start with \\
+ if (preg_match('[^external:\\\\]', $url)) {
+ return; //($this->_writeUrlExternal_net($row1, $col1, $row2, $col2, $url, $str, $format));
+ }
+
+ $record = 0x01B8; // Record identifier
+ $length = 0x00000; // Bytes to follow
+
+ if (!$format) {
+ $format = $this->_url_format;
+ }
+
+ // Strip URL type and change Unix dir separator to Dos style (if needed)
+ //
+ $url = preg_replace('/^external:/', '', $url);
+ $url = preg_replace('/\//', "\\", $url);
+
+ // Write the visible label
+ if ($str == '') {
+ $str = preg_replace('/\#/', ' - ', $url);
+ }
+ $str_error = $this->writeString($row1, $col1, $str, $format);
+ if (($str_error == -2) or ($str_error == -3)) {
+ return $str_error;
+ }
+
+ // Determine if the link is relative or absolute:
+ // relative if link contains no dir separator, "somefile.xls"
+ // relative if link starts with up-dir, "..\..\somefile.xls"
+ // otherwise, absolute
+
+ $absolute = 0x02; // Bit mask
+ if (!preg_match("/\\\/", $url)) {
+ $absolute = 0x00;
+ }
+ if (preg_match("/^\.\.\\\/", $url)) {
+ $absolute = 0x00;
+ }
+ $link_type = 0x01 | $absolute;
+
+ // Determine if the link contains a sheet reference and change some of the
+ // parameters accordingly.
+ // Split the dir name and sheet name (if it exists)
+ /*if (preg_match("/\#/", $url)) {
+ list($dir_long, $sheet) = split("\#", $url);
+ } else {
+ $dir_long = $url;
+ }
+
+ if (isset($sheet)) {
+ $link_type |= 0x08;
+ $sheet_len = pack("V", strlen($sheet) + 0x01);
+ $sheet = join("\0", split('', $sheet));
+ $sheet .= "\0\0\0";
+ } else {
+ $sheet_len = '';
+ $sheet = '';
+ }*/
+ $dir_long = $url;
+ if (preg_match("/\#/", $url)) {
+ $link_type |= 0x08;
+ }
+
+
+
+ // Pack the link type
+ $link_type = pack("V", $link_type);
+
+ // Calculate the up-level dir count e.g.. (..\..\..\ == 3)
+ $up_count = preg_match_all("/\.\.\\\/", $dir_long, $useless);
+ $up_count = pack("v", $up_count);
+
+ // Store the short dos dir name (null terminated)
+ $dir_short = preg_replace("/\.\.\\\/", '', $dir_long) . "\0";
+
+ // Store the long dir name as a wchar string (non-null terminated)
+ //$dir_long = join("\0", split('', $dir_long));
+ $dir_long = $dir_long . "\0";
+
+ // Pack the lengths of the dir strings
+ $dir_short_len = pack("V", strlen($dir_short) );
+ $dir_long_len = pack("V", strlen($dir_long) );
+ $stream_len = pack("V", 0);//strlen($dir_long) + 0x06);
+
+ // Pack the undocumented parts of the hyperlink stream
+ $unknown1 = pack("H*",'D0C9EA79F9BACE118C8200AA004BA90B02000000' );
+ $unknown2 = pack("H*",'0303000000000000C000000000000046' );
+ $unknown3 = pack("H*",'FFFFADDE000000000000000000000000000000000000000');
+ $unknown4 = pack("v", 0x03 );
+
+ // Pack the main data stream
+ $data = pack("vvvv", $row1, $row2, $col1, $col2) .
+ $unknown1 .
+ $link_type .
+ $unknown2 .
+ $up_count .
+ $dir_short_len.
+ $dir_short .
+ $unknown3 .
+ $stream_len ;/*.
+ $dir_long_len .
+ $unknown4 .
+ $dir_long .
+ $sheet_len .
+ $sheet ;*/
+
+ // Pack the header data
+ $length = strlen($data);
+ $header = pack("vv", $record, $length);
+
+ // Write the packed data
+ $this->_append($header. $data);
+ return($str_error);
+ }
+
+
+ /**
+ * This method is used to set the height and format for a row.
+ *
+ * @access public
+ * @param integer $row The row to set
+ * @param integer $height Height we are giving to the row.
+ * Use null to set XF without setting height
+ * @param mixed $format XF format we are giving to the row
+ * @param bool $hidden The optional hidden attribute
+ * @param integer $level The optional outline level for row, in range [0,7]
+ */
+ function setRow($row, $height, $format = null, $hidden = false, $level = 0)
+ {
+ $record = 0x0208; // Record identifier
+ $length = 0x0010; // Number of bytes to follow
+
+ $colMic = 0x0000; // First defined column
+ $colMac = 0x0000; // Last defined column
+ $irwMac = 0x0000; // Used by Excel to optimise loading
+ $reserved = 0x0000; // Reserved
+ $grbit = 0x0000; // Option flags
+ $ixfe = $this->_XF($format); // XF index
+
+ // set _row_sizes so _sizeRow() can use it
+ $this->_row_sizes[$row] = $height;
+
+ // Use setRow($row, null, $XF) to set XF format without setting height
+ if ($height != null) {
+ $miyRw = $height * 20; // row height
+ } else {
+ $miyRw = 0xff; // default row height is 256
+ }
+
+ $level = max(0, min($level, 7)); // level should be between 0 and 7
+ $this->_outline_row_level = max($level, $this->_outline_row_level);
+
+
+ // Set the options flags. fUnsynced is used to show that the font and row
+ // heights are not compatible. This is usually the case for WriteExcel.
+ // The collapsed flag 0x10 doesn't seem to be used to indicate that a row
+ // is collapsed. Instead it is used to indicate that the previous row is
+ // collapsed. The zero height flag, 0x20, is used to collapse a row.
+
+ $grbit |= $level;
+ if ($hidden) {
+ $grbit |= 0x0020;
+ }
+ $grbit |= 0x0040; // fUnsynced
+ if ($format) {
+ $grbit |= 0x0080;
+ }
+ $grbit |= 0x0100;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvvvvvv", $row, $colMic, $colMac, $miyRw,
+ $irwMac,$reserved, $grbit, $ixfe);
+ $this->_append($header.$data);
+ }
+
+ /**
+ * Writes Excel DIMENSIONS to define the area in which there is data.
+ *
+ * @access private
+ */
+ function _storeDimensions()
+ {
+ $record = 0x0200; // Record identifier
+ $row_min = $this->_dim_rowmin; // First row
+ $row_max = $this->_dim_rowmax + 1; // Last row plus 1
+ $col_min = $this->_dim_colmin; // First column
+ $col_max = $this->_dim_colmax + 1; // Last column plus 1
+ $reserved = 0x0000; // Reserved by Excel
+
+ if ($this->_BIFF_version == 0x0500) {
+ $length = 0x000A; // Number of bytes to follow
+ $data = pack("vvvvv", $row_min, $row_max,
+ $col_min, $col_max, $reserved);
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $length = 0x000E;
+ $data = pack("VVvvv", $row_min, $row_max,
+ $col_min, $col_max, $reserved);
+ }
+ $header = pack("vv", $record, $length);
+ $this->_prepend($header.$data);
+ }
+
+ /**
+ * Write BIFF record Window2.
+ *
+ * @access private
+ */
+ function _storeWindow2()
+ {
+ $record = 0x023E; // Record identifier
+ if ($this->_BIFF_version == 0x0500) {
+ $length = 0x000A; // Number of bytes to follow
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $length = 0x0012;
+ }
+
+ $grbit = 0x00B6; // Option flags
+ $rwTop = 0x0000; // Top row visible in window
+ $colLeft = 0x0000; // Leftmost column visible in window
+
+
+ // The options flags that comprise $grbit
+ $fDspFmla = 0; // 0 - bit
+ $fDspGrid = $this->_screen_gridlines; // 1
+ $fDspRwCol = 1; // 2
+ $fFrozen = $this->_frozen; // 3
+ $fDspZeros = 1; // 4
+ $fDefaultHdr = 1; // 5
+ $fArabic = 0; // 6
+ $fDspGuts = $this->_outline_on; // 7
+ $fFrozenNoSplit = 0; // 0 - bit
+ $fSelected = $this->selected; // 1
+ $fPaged = 1; // 2
+
+ $grbit = $fDspFmla;
+ $grbit |= $fDspGrid << 1;
+ $grbit |= $fDspRwCol << 2;
+ $grbit |= $fFrozen << 3;
+ $grbit |= $fDspZeros << 4;
+ $grbit |= $fDefaultHdr << 5;
+ $grbit |= $fArabic << 6;
+ $grbit |= $fDspGuts << 7;
+ $grbit |= $fFrozenNoSplit << 8;
+ $grbit |= $fSelected << 9;
+ $grbit |= $fPaged << 10;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvv", $grbit, $rwTop, $colLeft);
+ // FIXME !!!
+ if ($this->_BIFF_version == 0x0500) {
+ $rgbHdr = 0x00000000; // Row/column heading and gridline color
+ $data .= pack("V", $rgbHdr);
+ } elseif ($this->_BIFF_version == 0x0600) {
+ $rgbHdr = 0x0040; // Row/column heading and gridline color index
+ $zoom_factor_page_break = 0x0000;
+ $zoom_factor_normal = 0x0000;
+ $data .= pack("vvvvV", $rgbHdr, 0x0000, $zoom_factor_page_break, $zoom_factor_normal, 0x00000000);
+ }
+ $this->_append($header.$data);
+ }
+
+ /**
+ * Write BIFF record DEFCOLWIDTH if COLINFO records are in use.
+ *
+ * @access private
+ */
+ function _storeDefcol()
+ {
+ $record = 0x0055; // Record identifier
+ $length = 0x0002; // Number of bytes to follow
+ $colwidth = 0x0008; // Default column width
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $colwidth);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Write BIFF record COLINFO to define column widths
+ *
+ * Note: The SDK says the record length is 0x0B but Excel writes a 0x0C
+ * length record.
+ *
+ * @access private
+ * @param array $col_array This is the only parameter received and is composed of the following:
+ * 0 => First formatted column,
+ * 1 => Last formatted column,
+ * 2 => Col width (8.43 is Excel default),
+ * 3 => The optional XF format of the column,
+ * 4 => Option flags.
+ * 5 => Optional outline level
+ */
+ function _storeColinfo($col_array)
+ {
+ if (isset($col_array[0])) {
+ $colFirst = $col_array[0];
+ }
+ if (isset($col_array[1])) {
+ $colLast = $col_array[1];
+ }
+ if (isset($col_array[2])) {
+ $coldx = $col_array[2];
+ } else {
+ $coldx = 8.43;
+ }
+ if (isset($col_array[3])) {
+ $format = $col_array[3];
+ } else {
+ $format = 0;
+ }
+ if (isset($col_array[4])) {
+ $grbit = $col_array[4];
+ } else {
+ $grbit = 0;
+ }
+ if (isset($col_array[5])) {
+ $level = $col_array[5];
+ } else {
+ $level = 0;
+ }
+ $record = 0x007D; // Record identifier
+ $length = 0x000B; // Number of bytes to follow
+
+ $coldx += 0.72; // Fudge. Excel subtracts 0.72 !?
+ $coldx *= 256; // Convert to units of 1/256 of a char
+
+ $ixfe = $this->_XF($format);
+ $reserved = 0x00; // Reserved
+
+ $level = max(0, min($level, 7));
+ $grbit |= $level << 8;
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvvvC", $colFirst, $colLast, $coldx,
+ $ixfe, $grbit, $reserved);
+ $this->_prepend($header.$data);
+ }
+
+ /**
+ * Write BIFF record SELECTION.
+ *
+ * @access private
+ * @param array $array array containing ($rwFirst,$colFirst,$rwLast,$colLast)
+ * @see setSelection()
+ */
+ function _storeSelection($array)
+ {
+ list($rwFirst,$colFirst,$rwLast,$colLast) = $array;
+ $record = 0x001D; // Record identifier
+ $length = 0x000F; // Number of bytes to follow
+
+ $pnn = $this->_active_pane; // Pane position
+ $rwAct = $rwFirst; // Active row
+ $colAct = $colFirst; // Active column
+ $irefAct = 0; // Active cell ref
+ $cref = 1; // Number of refs
+
+ if (!isset($rwLast)) {
+ $rwLast = $rwFirst; // Last row in reference
+ }
+ if (!isset($colLast)) {
+ $colLast = $colFirst; // Last col in reference
+ }
+
+ // Swap last row/col for first row/col as necessary
+ if ($rwFirst > $rwLast) {
+ list($rwFirst, $rwLast) = array($rwLast, $rwFirst);
+ }
+
+ if ($colFirst > $colLast) {
+ list($colFirst, $colLast) = array($colLast, $colFirst);
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("CvvvvvvCC", $pnn, $rwAct, $colAct,
+ $irefAct, $cref,
+ $rwFirst, $rwLast,
+ $colFirst, $colLast);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Store the MERGEDCELLS record for all ranges of merged cells
+ *
+ * @access private
+ */
+ function _storeMergedCells()
+ {
+ // if there are no merged cell ranges set, return
+ if (count($this->_merged_ranges) == 0) {
+ return;
+ }
+ $record = 0x00E5;
+ $length = 2 + count($this->_merged_ranges) * 8;
+
+ $header = pack('vv', $record, $length);
+ $data = pack('v', count($this->_merged_ranges));
+ foreach ($this->_merged_ranges as $range) {
+ $data .= pack('vvvv', $range[0], $range[2], $range[1], $range[3]);
+ }
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Write BIFF record EXTERNCOUNT to indicate the number of external sheet
+ * references in a worksheet.
+ *
+ * Excel only stores references to external sheets that are used in formulas.
+ * For simplicity we store references to all the sheets in the workbook
+ * regardless of whether they are used or not. This reduces the overall
+ * complexity and eliminates the need for a two way dialogue between the formula
+ * parser the worksheet objects.
+ *
+ * @access private
+ * @param integer $count The number of external sheet references in this worksheet
+ */
+ function _storeExterncount($count)
+ {
+ $record = 0x0016; // Record identifier
+ $length = 0x0002; // Number of bytes to follow
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $count);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Writes the Excel BIFF EXTERNSHEET record. These references are used by
+ * formulas. A formula references a sheet name via an index. Since we store a
+ * reference to all of the external worksheets the EXTERNSHEET index is the same
+ * as the worksheet index.
+ *
+ * @access private
+ * @param string $sheetname The name of a external worksheet
+ */
+ function _storeExternsheet($sheetname)
+ {
+ $record = 0x0017; // Record identifier
+
+ // References to the current sheet are encoded differently to references to
+ // external sheets.
+ //
+ if ($this->name == $sheetname) {
+ $sheetname = '';
+ $length = 0x02; // The following 2 bytes
+ $cch = 1; // The following byte
+ $rgch = 0x02; // Self reference
+ } else {
+ $length = 0x02 + strlen($sheetname);
+ $cch = strlen($sheetname);
+ $rgch = 0x03; // Reference to a sheet in the current workbook
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("CC", $cch, $rgch);
+ $this->_prepend($header . $data . $sheetname);
+ }
+
+ /**
+ * Writes the Excel BIFF PANE record.
+ * The panes can either be frozen or thawed (unfrozen).
+ * Frozen panes are specified in terms of an integer number of rows and columns.
+ * Thawed panes are specified in terms of Excel's units for rows and columns.
+ *
+ * @access private
+ * @param array $panes This is the only parameter received and is composed of the following:
+ * 0 => Vertical split position,
+ * 1 => Horizontal split position
+ * 2 => Top row visible
+ * 3 => Leftmost column visible
+ * 4 => Active pane
+ */
+ function _storePanes($panes)
+ {
+ $y = $panes[0];
+ $x = $panes[1];
+ $rwTop = $panes[2];
+ $colLeft = $panes[3];
+ if (count($panes) > 4) { // if Active pane was received
+ $pnnAct = $panes[4];
+ } else {
+ $pnnAct = null;
+ }
+ $record = 0x0041; // Record identifier
+ $length = 0x000A; // Number of bytes to follow
+
+ // Code specific to frozen or thawed panes.
+ if ($this->_frozen) {
+ // Set default values for $rwTop and $colLeft
+ if (!isset($rwTop)) {
+ $rwTop = $y;
+ }
+ if (!isset($colLeft)) {
+ $colLeft = $x;
+ }
+ } else {
+ // Set default values for $rwTop and $colLeft
+ if (!isset($rwTop)) {
+ $rwTop = 0;
+ }
+ if (!isset($colLeft)) {
+ $colLeft = 0;
+ }
+
+ // Convert Excel's row and column units to the internal units.
+ // The default row height is 12.75
+ // The default column width is 8.43
+ // The following slope and intersection values were interpolated.
+ //
+ $y = 20*$y + 255;
+ $x = 113.879*$x + 390;
+ }
+
+
+ // Determine which pane should be active. There is also the undocumented
+ // option to override this should it be necessary: may be removed later.
+ //
+ if (!isset($pnnAct)) {
+ if ($x != 0 && $y != 0) {
+ $pnnAct = 0; // Bottom right
+ }
+ if ($x != 0 && $y == 0) {
+ $pnnAct = 1; // Top right
+ }
+ if ($x == 0 && $y != 0) {
+ $pnnAct = 2; // Bottom left
+ }
+ if ($x == 0 && $y == 0) {
+ $pnnAct = 3; // Top left
+ }
+ }
+
+ $this->_active_pane = $pnnAct; // Used in _storeSelection
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvvv", $x, $y, $rwTop, $colLeft, $pnnAct);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Store the page setup SETUP BIFF record.
+ *
+ * @access private
+ */
+ function _storeSetup()
+ {
+ $record = 0x00A1; // Record identifier
+ $length = 0x0022; // Number of bytes to follow
+
+ $iPaperSize = $this->_paper_size; // Paper size
+ $iScale = $this->_print_scale; // Print scaling factor
+ $iPageStart = 0x01; // Starting page number
+ $iFitWidth = $this->_fit_width; // Fit to number of pages wide
+ $iFitHeight = $this->_fit_height; // Fit to number of pages high
+ $grbit = 0x00; // Option flags
+ $iRes = 0x0258; // Print resolution
+ $iVRes = 0x0258; // Vertical print resolution
+ $numHdr = $this->_margin_head; // Header Margin
+ $numFtr = $this->_margin_foot; // Footer Margin
+ $iCopies = 0x01; // Number of copies
+
+ $fLeftToRight = 0x0; // Print over then down
+ $fLandscape = $this->_orientation; // Page orientation
+ $fNoPls = 0x0; // Setup not read from printer
+ $fNoColor = 0x0; // Print black and white
+ $fDraft = 0x0; // Print draft quality
+ $fNotes = 0x0; // Print notes
+ $fNoOrient = 0x0; // Orientation not set
+ $fUsePage = 0x0; // Use custom starting page
+
+ $grbit = $fLeftToRight;
+ $grbit |= $fLandscape << 1;
+ $grbit |= $fNoPls << 2;
+ $grbit |= $fNoColor << 3;
+ $grbit |= $fDraft << 4;
+ $grbit |= $fNotes << 5;
+ $grbit |= $fNoOrient << 6;
+ $grbit |= $fUsePage << 7;
+
+ $numHdr = pack("d", $numHdr);
+ $numFtr = pack("d", $numFtr);
+ if ($this->_byte_order) { // if it's Big Endian
+ $numHdr = strrev($numHdr);
+ $numFtr = strrev($numFtr);
+ }
+
+ $header = pack("vv", $record, $length);
+ $data1 = pack("vvvvvvvv", $iPaperSize,
+ $iScale,
+ $iPageStart,
+ $iFitWidth,
+ $iFitHeight,
+ $grbit,
+ $iRes,
+ $iVRes);
+ $data2 = $numHdr.$numFtr;
+ $data3 = pack("v", $iCopies);
+ $this->_prepend($header . $data1 . $data2 . $data3);
+ }
+
+ /**
+ * Store the header caption BIFF record.
+ *
+ * @access private
+ */
+ function _storeHeader()
+ {
+ $record = 0x0014; // Record identifier
+
+ $str = $this->_header; // header string
+ $cch = strlen($str); // Length of header string
+ if ($this->_BIFF_version == 0x0600) {
+ $encoding = 0x0; // TODO: Unicode support
+ $length = 3 + $cch; // Bytes to follow
+ } else {
+ $length = 1 + $cch; // Bytes to follow
+ }
+
+ $header = pack("vv", $record, $length);
+ if ($this->_BIFF_version == 0x0600) {
+ $data = pack("vC", $cch, $encoding);
+ } else {
+ $data = pack("C", $cch);
+ }
+
+ $this->_prepend($header.$data.$str);
+ }
+
+ /**
+ * Store the footer caption BIFF record.
+ *
+ * @access private
+ */
+ function _storeFooter()
+ {
+ $record = 0x0015; // Record identifier
+
+ $str = $this->_footer; // Footer string
+ $cch = strlen($str); // Length of footer string
+ if ($this->_BIFF_version == 0x0600) {
+ $encoding = 0x0; // TODO: Unicode support
+ $length = 3 + $cch; // Bytes to follow
+ } else {
+ $length = 1 + $cch;
+ }
+
+ $header = pack("vv", $record, $length);
+ if ($this->_BIFF_version == 0x0600) {
+ $data = pack("vC", $cch, $encoding);
+ } else {
+ $data = pack("C", $cch);
+ }
+
+ $this->_prepend($header . $data . $str);
+ }
+
+ /**
+ * Store the horizontal centering HCENTER BIFF record.
+ *
+ * @access private
+ */
+ function _storeHcenter()
+ {
+ $record = 0x0083; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $fHCenter = $this->_hcenter; // Horizontal centering
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $fHCenter);
+
+ $this->_prepend($header.$data);
+ }
+
+ /**
+ * Store the vertical centering VCENTER BIFF record.
+ *
+ * @access private
+ */
+ function _storeVcenter()
+ {
+ $record = 0x0084; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $fVCenter = $this->_vcenter; // Horizontal centering
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $fVCenter);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Store the LEFTMARGIN BIFF record.
+ *
+ * @access private
+ */
+ function _storeMarginLeft()
+ {
+ $record = 0x0026; // Record identifier
+ $length = 0x0008; // Bytes to follow
+
+ $margin = $this->_margin_left; // Margin in inches
+
+ $header = pack("vv", $record, $length);
+ $data = pack("d", $margin);
+ if ($this->_byte_order) { // if it's Big Endian
+ $data = strrev($data);
+ }
+
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Store the RIGHTMARGIN BIFF record.
+ *
+ * @access private
+ */
+ function _storeMarginRight()
+ {
+ $record = 0x0027; // Record identifier
+ $length = 0x0008; // Bytes to follow
+
+ $margin = $this->_margin_right; // Margin in inches
+
+ $header = pack("vv", $record, $length);
+ $data = pack("d", $margin);
+ if ($this->_byte_order) { // if it's Big Endian
+ $data = strrev($data);
+ }
+
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Store the TOPMARGIN BIFF record.
+ *
+ * @access private
+ */
+ function _storeMarginTop()
+ {
+ $record = 0x0028; // Record identifier
+ $length = 0x0008; // Bytes to follow
+
+ $margin = $this->_margin_top; // Margin in inches
+
+ $header = pack("vv", $record, $length);
+ $data = pack("d", $margin);
+ if ($this->_byte_order) { // if it's Big Endian
+ $data = strrev($data);
+ }
+
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Store the BOTTOMMARGIN BIFF record.
+ *
+ * @access private
+ */
+ function _storeMarginBottom()
+ {
+ $record = 0x0029; // Record identifier
+ $length = 0x0008; // Bytes to follow
+
+ $margin = $this->_margin_bottom; // Margin in inches
+
+ $header = pack("vv", $record, $length);
+ $data = pack("d", $margin);
+ if ($this->_byte_order) { // if it's Big Endian
+ $data = strrev($data);
+ }
+
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Merges the area given by its arguments.
+ * This is an Excel97/2000 method. It is required to perform more complicated
+ * merging than the normal setAlign('merge').
+ *
+ * @access public
+ * @param integer $first_row First row of the area to merge
+ * @param integer $first_col First column of the area to merge
+ * @param integer $last_row Last row of the area to merge
+ * @param integer $last_col Last column of the area to merge
+ */
+ function mergeCells($first_row, $first_col, $last_row, $last_col)
+ {
+ $record = 0x00E5; // Record identifier
+ $length = 0x000A; // Bytes to follow
+ $cref = 1; // Number of refs
+
+ // Swap last row/col for first row/col as necessary
+ if ($first_row > $last_row) {
+ list($first_row, $last_row) = array($last_row, $first_row);
+ }
+
+ if ($first_col > $last_col) {
+ list($first_col, $last_col) = array($last_col, $first_col);
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvvv", $cref, $first_row, $last_row,
+ $first_col, $last_col);
+
+ $this->_append($header.$data);
+ }
+
+ /**
+ * Write the PRINTHEADERS BIFF record.
+ *
+ * @access private
+ */
+ function _storePrintHeaders()
+ {
+ $record = 0x002a; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $fPrintRwCol = $this->_print_headers; // Boolean flag
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $fPrintRwCol);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the
+ * GRIDSET record.
+ *
+ * @access private
+ */
+ function _storePrintGridlines()
+ {
+ $record = 0x002b; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $fPrintGrid = $this->_print_gridlines; // Boolean flag
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $fPrintGrid);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Write the GRIDSET BIFF record. Must be used in conjunction with the
+ * PRINTGRIDLINES record.
+ *
+ * @access private
+ */
+ function _storeGridset()
+ {
+ $record = 0x0082; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $fGridSet = !($this->_print_gridlines); // Boolean flag
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $fGridSet);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Write the GUTS BIFF record. This is used to configure the gutter margins
+ * where Excel outline symbols are displayed. The visibility of the gutters is
+ * controlled by a flag in WSBOOL.
+ *
+ * @see _storeWsbool()
+ * @access private
+ */
+ function _storeGuts()
+ {
+ $record = 0x0080; // Record identifier
+ $length = 0x0008; // Bytes to follow
+
+ $dxRwGut = 0x0000; // Size of row gutter
+ $dxColGut = 0x0000; // Size of col gutter
+
+ $row_level = $this->_outline_row_level;
+ $col_level = 0;
+
+ // Calculate the maximum column outline level. The equivalent calculation
+ // for the row outline level is carried out in setRow().
+ $colcount = count($this->_colinfo);
+ for ($i = 0; $i < $colcount; $i++) {
+ // Skip cols without outline level info.
+ if (@count($col_level) >= 6) {
+ $col_level = max($this->_colinfo[$i][5], $col_level);
+ }
+ }
+
+ // Set the limits for the outline levels (0 <= x <= 7).
+ $col_level = max(0, min($col_level, 7));
+
+ // The displayed level is one greater than the max outline levels
+ if ($row_level) {
+ $row_level++;
+ }
+ if ($col_level) {
+ $col_level++;
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvv", $dxRwGut, $dxColGut, $row_level, $col_level);
+
+ $this->_prepend($header.$data);
+ }
+
+
+ /**
+ * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction
+ * with the SETUP record.
+ *
+ * @access private
+ */
+ function _storeWsbool()
+ {
+ $record = 0x0081; // Record identifier
+ $length = 0x0002; // Bytes to follow
+ $grbit = 0x0000;
+
+ // The only option that is of interest is the flag for fit to page. So we
+ // set all the options in one go.
+ //
+ /*if ($this->_fit_page) {
+ $grbit = 0x05c1;
+ } else {
+ $grbit = 0x04c1;
+ }*/
+ // Set the option flags
+ $grbit |= 0x0001; // Auto page breaks visible
+ if ($this->_outline_style) {
+ $grbit |= 0x0020; // Auto outline styles
+ }
+ if ($this->_outline_below) {
+ $grbit |= 0x0040; // Outline summary below
+ }
+ if ($this->_outline_right) {
+ $grbit |= 0x0080; // Outline summary right
+ }
+ if ($this->_fit_page) {
+ $grbit |= 0x0100; // Page setup fit to page
+ }
+ if ($this->_outline_on) {
+ $grbit |= 0x0400; // Outline symbols displayed
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $grbit);
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Write the HORIZONTALPAGEBREAKS BIFF record.
+ *
+ * @access private
+ */
+ function _storeHbreak()
+ {
+ // Return if the user hasn't specified pagebreaks
+ if (empty($this->_hbreaks)) {
+ return;
+ }
+
+ // Sort and filter array of page breaks
+ $breaks = $this->_hbreaks;
+ sort($breaks, SORT_NUMERIC);
+ if ($breaks[0] == 0) { // don't use first break if it's 0
+ array_shift($breaks);
+ }
+
+ $record = 0x001b; // Record identifier
+ $cbrk = count($breaks); // Number of page breaks
+ if ($this->_BIFF_version == 0x0600) {
+ $length = 2 + 6*$cbrk; // Bytes to follow
+ } else {
+ $length = 2 + 2*$cbrk; // Bytes to follow
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $cbrk);
+
+ // Append each page break
+ foreach ($breaks as $break) {
+ if ($this->_BIFF_version == 0x0600) {
+ $data .= pack("vvv", $break, 0x0000, 0x00ff);
+ } else {
+ $data .= pack("v", $break);
+ }
+ }
+
+ $this->_prepend($header.$data);
+ }
+
+
+ /**
+ * Write the VERTICALPAGEBREAKS BIFF record.
+ *
+ * @access private
+ */
+ function _storeVbreak()
+ {
+ // Return if the user hasn't specified pagebreaks
+ if (empty($this->_vbreaks)) {
+ return;
+ }
+
+ // 1000 vertical pagebreaks appears to be an internal Excel 5 limit.
+ // It is slightly higher in Excel 97/200, approx. 1026
+ $breaks = array_slice($this->_vbreaks,0,1000);
+
+ // Sort and filter array of page breaks
+ sort($breaks, SORT_NUMERIC);
+ if ($breaks[0] == 0) { // don't use first break if it's 0
+ array_shift($breaks);
+ }
+
+ $record = 0x001a; // Record identifier
+ $cbrk = count($breaks); // Number of page breaks
+ if ($this->_BIFF_version == 0x0600) {
+ $length = 2 + 6*$cbrk; // Bytes to follow
+ } else {
+ $length = 2 + 2*$cbrk; // Bytes to follow
+ }
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $cbrk);
+
+ // Append each page break
+ foreach ($breaks as $break) {
+ if ($this->_BIFF_version == 0x0600) {
+ $data .= pack("vvv", $break, 0x0000, 0xffff);
+ } else {
+ $data .= pack("v", $break);
+ }
+ }
+
+ $this->_prepend($header . $data);
+ }
+
+ /**
+ * Set the Biff PROTECT record to indicate that the worksheet is protected.
+ *
+ * @access private
+ */
+ function _storeProtect()
+ {
+ // Exit unless sheet protection has been specified
+ if ($this->_protect == 0) {
+ return;
+ }
+
+ $record = 0x0012; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $fLock = $this->_protect; // Worksheet is protected
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $fLock);
+
+ $this->_prepend($header.$data);
+ }
+
+ /**
+ * Write the worksheet PASSWORD record.
+ *
+ * @access private
+ */
+ function _storePassword()
+ {
+ // Exit unless sheet protection and password have been specified
+ if (($this->_protect == 0) || (!isset($this->_password))) {
+ return;
+ }
+
+ $record = 0x0013; // Record identifier
+ $length = 0x0002; // Bytes to follow
+
+ $wPassword = $this->_password; // Encoded password
+
+ $header = pack("vv", $record, $length);
+ $data = pack("v", $wPassword);
+
+ $this->_prepend($header . $data);
+ }
+
+
+ /**
+ * Insert a 24bit bitmap image in a worksheet.
+ *
+ * @access public
+ * @param integer $row The row we are going to insert the bitmap into
+ * @param integer $col The column we are going to insert the bitmap into
+ * @param string $bitmap The bitmap filename
+ * @param integer $x The horizontal position (offset) of the image inside the cell.
+ * @param integer $y The vertical position (offset) of the image inside the cell.
+ * @param integer $scale_x The horizontal scale
+ * @param integer $scale_y The vertical scale
+ */
+ function insertBitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1)
+ {
+ $bitmap_array = $this->_processBitmap($bitmap);
+ if ($this->isError($bitmap_array)) {
+ $this->writeString($row, $col, $bitmap_array->getMessage());
+ return;
+ }
+ list($width, $height, $size, $data) = $bitmap_array; //$this->_processBitmap($bitmap);
+
+ // Scale the frame of the image.
+ $width *= $scale_x;
+ $height *= $scale_y;
+
+ // Calculate the vertices of the image and write the OBJ record
+ $this->_positionImage($col, $row, $x, $y, $width, $height);
+
+ // Write the IMDATA record to store the bitmap data
+ $record = 0x007f;
+ $length = 8 + $size;
+ $cf = 0x09;
+ $env = 0x01;
+ $lcb = $size;
+
+ $header = pack("vvvvV", $record, $length, $cf, $env, $lcb);
+ $this->_append($header.$data);
+ }
+
+ /**
+ * Calculate the vertices that define the position of the image as required by
+ * the OBJ record.
+ *
+ * +------------+------------+
+ * | A | B |
+ * +-----+------------+------------+
+ * | |(x1,y1) | |
+ * | 1 |(A1)._______|______ |
+ * | | | | |
+ * | | | | |
+ * +-----+----| BITMAP |-----+
+ * | | | | |
+ * | 2 | |______________. |
+ * | | | (B2)|
+ * | | | (x2,y2)|
+ * +---- +------------+------------+
+ *
+ * Example of a bitmap that covers some of the area from cell A1 to cell B2.
+ *
+ * Based on the width and height of the bitmap we need to calculate 8 vars:
+ * $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2.
+ * The width and height of the cells are also variable and have to be taken into
+ * account.
+ * The values of $col_start and $row_start are passed in from the calling
+ * function. The values of $col_end and $row_end are calculated by subtracting
+ * the width and height of the bitmap from the width and height of the
+ * underlying cells.
+ * The vertices are expressed as a percentage of the underlying cell width as
+ * follows (rhs values are in pixels):
+ *
+ * x1 = X / W *1024
+ * y1 = Y / H *256
+ * x2 = (X-1) / W *1024
+ * y2 = (Y-1) / H *256
+ *
+ * Where: X is distance from the left side of the underlying cell
+ * Y is distance from the top of the underlying cell
+ * W is the width of the cell
+ * H is the height of the cell
+ *
+ * @access private
+ * @note the SDK incorrectly states that the height should be expressed as a
+ * percentage of 1024.
+ * @param integer $col_start Col containing upper left corner of object
+ * @param integer $row_start Row containing top left corner of object
+ * @param integer $x1 Distance to left side of object
+ * @param integer $y1 Distance to top of object
+ * @param integer $width Width of image frame
+ * @param integer $height Height of image frame
+ */
+ function _positionImage($col_start, $row_start, $x1, $y1, $width, $height)
+ {
+ // Initialise end cell to the same as the start cell
+ $col_end = $col_start; // Col containing lower right corner of object
+ $row_end = $row_start; // Row containing bottom right corner of object
+
+ // Zero the specified offset if greater than the cell dimensions
+ if ($x1 >= $this->_sizeCol($col_start)) {
+ $x1 = 0;
+ }
+ if ($y1 >= $this->_sizeRow($row_start)) {
+ $y1 = 0;
+ }
+
+ $width = $width + $x1 -1;
+ $height = $height + $y1 -1;
+
+ // Subtract the underlying cell widths to find the end cell of the image
+ while ($width >= $this->_sizeCol($col_end)) {
+ $width -= $this->_sizeCol($col_end);
+ $col_end++;
+ }
+
+ // Subtract the underlying cell heights to find the end cell of the image
+ while ($height >= $this->_sizeRow($row_end)) {
+ $height -= $this->_sizeRow($row_end);
+ $row_end++;
+ }
+
+ // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
+ // with zero eight or width.
+ //
+ if ($this->_sizeCol($col_start) == 0) {
+ return;
+ }
+ if ($this->_sizeCol($col_end) == 0) {
+ return;
+ }
+ if ($this->_sizeRow($row_start) == 0) {
+ return;
+ }
+ if ($this->_sizeRow($row_end) == 0) {
+ return;
+ }
+
+ // Convert the pixel values to the percentage value expected by Excel
+ $x1 = $x1 / $this->_sizeCol($col_start) * 1024;
+ $y1 = $y1 / $this->_sizeRow($row_start) * 256;
+ $x2 = $width / $this->_sizeCol($col_end) * 1024; // Distance to right side of object
+ $y2 = $height / $this->_sizeRow($row_end) * 256; // Distance to bottom of object
+
+ $this->_storeObjPicture($col_start, $x1,
+ $row_start, $y1,
+ $col_end, $x2,
+ $row_end, $y2);
+ }
+
+ /**
+ * Convert the width of a cell from user's units to pixels. By interpolation
+ * the relationship is: y = 7x +5. If the width hasn't been set by the user we
+ * use the default value. If the col is hidden we use a value of zero.
+ *
+ * @access private
+ * @param integer $col The column
+ * @return integer The width in pixels
+ */
+ function _sizeCol($col)
+ {
+ // Look up the cell value to see if it has been changed
+ if (isset($this->col_sizes[$col])) {
+ if ($this->col_sizes[$col] == 0) {
+ return(0);
+ } else {
+ return(floor(7 * $this->col_sizes[$col] + 5));
+ }
+ } else {
+ return(64);
+ }
+ }
+
+ /**
+ * Convert the height of a cell from user's units to pixels. By interpolation
+ * the relationship is: y = 4/3x. If the height hasn't been set by the user we
+ * use the default value. If the row is hidden we use a value of zero. (Not
+ * possible to hide row yet).
+ *
+ * @access private
+ * @param integer $row The row
+ * @return integer The width in pixels
+ */
+ function _sizeRow($row)
+ {
+ // Look up the cell value to see if it has been changed
+ if (isset($this->_row_sizes[$row])) {
+ if ($this->_row_sizes[$row] == 0) {
+ return(0);
+ } else {
+ return(floor(4/3 * $this->_row_sizes[$row]));
+ }
+ } else {
+ return(17);
+ }
+ }
+
+ /**
+ * Store the OBJ record that precedes an IMDATA record. This could be generalise
+ * to support other Excel objects.
+ *
+ * @access private
+ * @param integer $colL Column containing upper left corner of object
+ * @param integer $dxL Distance from left side of cell
+ * @param integer $rwT Row containing top left corner of object
+ * @param integer $dyT Distance from top of cell
+ * @param integer $colR Column containing lower right corner of object
+ * @param integer $dxR Distance from right of cell
+ * @param integer $rwB Row containing bottom right corner of object
+ * @param integer $dyB Distance from bottom of cell
+ */
+ function _storeObjPicture($colL,$dxL,$rwT,$dyT,$colR,$dxR,$rwB,$dyB)
+ {
+ $record = 0x005d; // Record identifier
+ $length = 0x003c; // Bytes to follow
+
+ $cObj = 0x0001; // Count of objects in file (set to 1)
+ $OT = 0x0008; // Object type. 8 = Picture
+ $id = 0x0001; // Object ID
+ $grbit = 0x0614; // Option flags
+
+ $cbMacro = 0x0000; // Length of FMLA structure
+ $Reserved1 = 0x0000; // Reserved
+ $Reserved2 = 0x0000; // Reserved
+
+ $icvBack = 0x09; // Background colour
+ $icvFore = 0x09; // Foreground colour
+ $fls = 0x00; // Fill pattern
+ $fAuto = 0x00; // Automatic fill
+ $icv = 0x08; // Line colour
+ $lns = 0xff; // Line style
+ $lnw = 0x01; // Line weight
+ $fAutoB = 0x00; // Automatic border
+ $frs = 0x0000; // Frame style
+ $cf = 0x0009; // Image format, 9 = bitmap
+ $Reserved3 = 0x0000; // Reserved
+ $cbPictFmla = 0x0000; // Length of FMLA structure
+ $Reserved4 = 0x0000; // Reserved
+ $grbit2 = 0x0001; // Option flags
+ $Reserved5 = 0x0000; // Reserved
+
+
+ $header = pack("vv", $record, $length);
+ $data = pack("V", $cObj);
+ $data .= pack("v", $OT);
+ $data .= pack("v", $id);
+ $data .= pack("v", $grbit);
+ $data .= pack("v", $colL);
+ $data .= pack("v", $dxL);
+ $data .= pack("v", $rwT);
+ $data .= pack("v", $dyT);
+ $data .= pack("v", $colR);
+ $data .= pack("v", $dxR);
+ $data .= pack("v", $rwB);
+ $data .= pack("v", $dyB);
+ $data .= pack("v", $cbMacro);
+ $data .= pack("V", $Reserved1);
+ $data .= pack("v", $Reserved2);
+ $data .= pack("C", $icvBack);
+ $data .= pack("C", $icvFore);
+ $data .= pack("C", $fls);
+ $data .= pack("C", $fAuto);
+ $data .= pack("C", $icv);
+ $data .= pack("C", $lns);
+ $data .= pack("C", $lnw);
+ $data .= pack("C", $fAutoB);
+ $data .= pack("v", $frs);
+ $data .= pack("V", $cf);
+ $data .= pack("v", $Reserved3);
+ $data .= pack("v", $cbPictFmla);
+ $data .= pack("v", $Reserved4);
+ $data .= pack("v", $grbit2);
+ $data .= pack("V", $Reserved5);
+
+ $this->_append($header . $data);
+ }
+
+ /**
+ * Convert a 24 bit bitmap into the modified internal format used by Windows.
+ * This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
+ * MSDN library.
+ *
+ * @access private
+ * @param string $bitmap The bitmap to process
+ * @return array Array with data and properties of the bitmap
+ */
+ function _processBitmap($bitmap)
+ {
+ // Open file.
+ $bmp_fd = @fopen($bitmap,"rb");
+ if (!$bmp_fd) {
+ $this->raiseError("Couldn't import $bitmap");
+ }
+
+ // Slurp the file into a string.
+ $data = fread($bmp_fd, filesize($bitmap));
+
+ // Check that the file is big enough to be a bitmap.
+ if (strlen($data) <= 0x36) {
+ $this->raiseError("$bitmap doesn't contain enough data.\n");
+ }
+
+ // The first 2 bytes are used to identify the bitmap.
+ $identity = unpack("A2ident", $data);
+ if ($identity['ident'] != "BM") {
+ $this->raiseError("$bitmap doesn't appear to be a valid bitmap image.\n");
+ }
+
+ // Remove bitmap data: ID.
+ $data = substr($data, 2);
+
+ // Read and remove the bitmap size. This is more reliable than reading
+ // the data size at offset 0x22.
+ //
+ $size_array = unpack("Vsa", substr($data, 0, 4));
+ $size = $size_array['sa'];
+ $data = substr($data, 4);
+ $size -= 0x36; // Subtract size of bitmap header.
+ $size += 0x0C; // Add size of BIFF header.
+
+ // Remove bitmap data: reserved, offset, header length.
+ $data = substr($data, 12);
+
+ // Read and remove the bitmap width and height. Verify the sizes.
+ $width_and_height = unpack("V2", substr($data, 0, 8));
+ $width = $width_and_height[1];
+ $height = $width_and_height[2];
+ $data = substr($data, 8);
+ if ($width > 0xFFFF) {
+ $this->raiseError("$bitmap: largest image width supported is 65k.\n");
+ }
+ if ($height > 0xFFFF) {
+ $this->raiseError("$bitmap: largest image height supported is 65k.\n");
+ }
+
+ // Read and remove the bitmap planes and bpp data. Verify them.
+ $planes_and_bitcount = unpack("v2", substr($data, 0, 4));
+ $data = substr($data, 4);
+ if ($planes_and_bitcount[2] != 24) { // Bitcount
+ $this->raiseError("$bitmap isn't a 24bit true color bitmap.\n");
+ }
+ if ($planes_and_bitcount[1] != 1) {
+ $this->raiseError("$bitmap: only 1 plane supported in bitmap image.\n");
+ }
+
+ // Read and remove the bitmap compression. Verify compression.
+ $compression = unpack("Vcomp", substr($data, 0, 4));
+ $data = substr($data, 4);
+
+ //$compression = 0;
+ if ($compression['comp'] != 0) {
+ $this->raiseError("$bitmap: compression not supported in bitmap image.\n");
+ }
+
+ // Remove bitmap data: data size, hres, vres, colours, imp. colours.
+ $data = substr($data, 20);
+
+ // Add the BITMAPCOREHEADER data
+ $header = pack("Vvvvv", 0x000c, $width, $height, 0x01, 0x18);
+ $data = $header . $data;
+
+ return (array($width, $height, $size, $data));
+ }
+
+ /**
+ * Store the window zoom factor. This should be a reduced fraction but for
+ * simplicity we will store all fractions with a numerator of 100.
+ *
+ * @access private
+ */
+ function _storeZoom()
+ {
+ // If scale is 100 we don't need to write a record
+ if ($this->_zoom == 100) {
+ return;
+ }
+
+ $record = 0x00A0; // Record identifier
+ $length = 0x0004; // Bytes to follow
+
+ $header = pack("vv", $record, $length);
+ $data = pack("vv", $this->_zoom, 100);
+ $this->_append($header . $data);
+ }
+
+ /**
+ * FIXME: add comments
+ */
+ function setValidation($row1, $col1, $row2, $col2, &$validator)
+ {
+ $this->_dv[] = $validator->_getData() .
+ pack("vvvvv", 1, $row1, $row2, $col1, $col2);
+ }
+
+ /**
+ * Store the DVAL and DV records.
+ *
+ * @access private
+ */
+ function _storeDataValidity()
+ {
+ $record = 0x01b2; // Record identifier
+ $length = 0x0012; // Bytes to follow
+
+ $grbit = 0x0002; // Prompt box at cell, no cached validity data at DV records
+ $horPos = 0x00000000; // Horizontal position of prompt box, if fixed position
+ $verPos = 0x00000000; // Vertical position of prompt box, if fixed position
+ $objId = 0xffffffff; // Object identifier of drop down arrow object, or -1 if not visible
+
+ $header = pack('vv', $record, $length);
+ $data = pack('vVVVV', $grbit, $horPos, $verPos, $objId,
+ count($this->_dv));
+ $this->_append($header.$data);
+
+ $record = 0x01be; // Record identifier
+ foreach ($this->_dv as $dv) {
+ $length = strlen($dv); // Bytes to follow
+ $header = pack("vv", $record, $length);
+ $this->_append($header . $dv);
+ }
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/OLE.php b/vendor/library/Excel/phpxls/OLE.php
new file mode 100644
index 0000000..ee662ff
--- /dev/null
+++ b/vendor/library/Excel/phpxls/OLE.php
@@ -0,0 +1,570 @@
+ |
+// | Based on OLE::Storage_Lite by Kawai, Takanori |
+// +----------------------------------------------------------------------+
+//
+// $Id: OLE.php,v 1.15 2007/12/18 20:59:11 schmidt Exp $
+
+
+/**
+* Constants for OLE package
+*/
+define('OLE_PPS_TYPE_ROOT', 5);
+define('OLE_PPS_TYPE_DIR', 1);
+define('OLE_PPS_TYPE_FILE', 2);
+define('OLE_DATA_SIZE_SMALL', 0x1000);
+define('OLE_LONG_INT_SIZE', 4);
+define('OLE_PPS_SIZE', 0x80);
+
+require_once 'PEAR.php';
+
+/**
+* Array for storing OLE instances that are accessed from
+* OLE_ChainedBlockStream::stream_open().
+* @var array
+*/
+$GLOBALS['_OLE_INSTANCES'] = array();
+
+/**
+* OLE package base class.
+*
+* @category Structures
+* @package OLE
+* @author Xavier Noguer
+* @author Christian Schmidt
+*/
+class OLE extends PEAR
+{
+
+ /**
+ * The file handle for reading an OLE container
+ * @var resource
+ */
+ var $_file_handle;
+
+ /**
+ * Array of PPS's found on the OLE container
+ * @var array
+ */
+ var $_list;
+
+ /**
+ * Root directory of OLE container
+ * @var OLE_PPS_Root
+ */
+ var $root;
+
+ /**
+ * Big Block Allocation Table
+ * @var array (blockId => nextBlockId)
+ */
+ var $bbat;
+
+ /**
+ * Short Block Allocation Table
+ * @var array (blockId => nextBlockId)
+ */
+ var $sbat;
+
+ /**
+ * Size of big blocks. This is usually 512.
+ * @var int number of octets per block.
+ */
+ var $bigBlockSize;
+
+ /**
+ * Size of small blocks. This is usually 64.
+ * @var int number of octets per block
+ */
+ var $smallBlockSize;
+
+ /**
+ * Creates a new OLE object
+ * @access public
+ */
+ function __construct()
+ {
+ $this->_list = array();
+ }
+
+ /**
+ * Destructor (using PEAR)
+ * Just closes the file handle on the OLE file.
+ *
+ * @access private
+ */
+ function _OLE()
+ {
+ fclose($this->_file_handle);
+ }
+
+ /**
+ * Reads an OLE container from the contents of the file given.
+ *
+ * @access public
+ * @param string $file
+ * @return mixed true on success, PEAR_Error on failure
+ */
+ function read($file)
+ {
+ $fh = @fopen($file, "r");
+ if (!$fh) {
+ return $this->raiseError("Can't open file $file");
+ }
+ $this->_file_handle = $fh;
+
+ $signature = fread($fh, 8);
+ if ("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" != $signature) {
+ return $this->raiseError("File doesn't seem to be an OLE container.");
+ }
+ fseek($fh, 28);
+ if (fread($fh, 2) != "\xFE\xFF") {
+ // This shouldn't be a problem in practice
+ return $this->raiseError("Only Little-Endian encoding is supported.");
+ }
+ // Size of blocks and short blocks in bytes
+ $this->bigBlockSize = pow(2, $this->_readInt2($fh));
+ $this->smallBlockSize = pow(2, $this->_readInt2($fh));
+
+ // Skip UID, revision number and version number
+ fseek($fh, 44);
+ // Number of blocks in Big Block Allocation Table
+ $bbatBlockCount = $this->_readInt4($fh);
+
+ // Root chain 1st block
+ $directoryFirstBlockId = $this->_readInt4($fh);
+
+ // Skip unused bytes
+ fseek($fh, 56);
+ // Streams shorter than this are stored using small blocks
+ $this->bigBlockThreshold = $this->_readInt4($fh);
+ // Block id of first sector in Short Block Allocation Table
+ $sbatFirstBlockId = $this->_readInt4($fh);
+ // Number of blocks in Short Block Allocation Table
+ $sbbatBlockCount = $this->_readInt4($fh);
+ // Block id of first sector in Master Block Allocation Table
+ $mbatFirstBlockId = $this->_readInt4($fh);
+ // Number of blocks in Master Block Allocation Table
+ $mbbatBlockCount = $this->_readInt4($fh);
+ $this->bbat = array();
+
+ // Remaining 4 * 109 bytes of current block is beginning of Master
+ // Block Allocation Table
+ $mbatBlocks = array();
+ for ($i = 0; $i < 109; $i++) {
+ $mbatBlocks[] = $this->_readInt4($fh);
+ }
+
+ // Read rest of Master Block Allocation Table (if any is left)
+ $pos = $this->_getBlockOffset($mbatFirstBlockId);
+ for ($i = 0; $i < $mbbatBlockCount; $i++) {
+ fseek($fh, $pos);
+ for ($j = 0; $j < $this->bigBlockSize / 4 - 1; $j++) {
+ $mbatBlocks[] = $this->_readInt4($fh);
+ }
+ // Last block id in each block points to next block
+ $pos = $this->_getBlockOffset($this->_readInt4($fh));
+ }
+
+ // Read Big Block Allocation Table according to chain specified by
+ // $mbatBlocks
+ for ($i = 0; $i < $bbatBlockCount; $i++) {
+ $pos = $this->_getBlockOffset($mbatBlocks[$i]);
+ fseek($fh, $pos);
+ for ($j = 0 ; $j < $this->bigBlockSize / 4; $j++) {
+ $this->bbat[] = $this->_readInt4($fh);
+ }
+ }
+
+ // Read short block allocation table (SBAT)
+ $this->sbat = array();
+ $shortBlockCount = $sbbatBlockCount * $this->bigBlockSize / 4;
+ $sbatFh = $this->getStream($sbatFirstBlockId);
+ for ($blockId = 0; $blockId < $shortBlockCount; $blockId++) {
+ $this->sbat[$blockId] = $this->_readInt4($sbatFh);
+ }
+ fclose($sbatFh);
+
+ $this->_readPpsWks($directoryFirstBlockId);
+
+ return true;
+ }
+
+ /**
+ * @param int $blockId block id
+ * @return int byte offset from beginning of file
+ * @access private
+ */
+ function _getBlockOffset($blockId)
+ {
+ return 512 + $blockId * $this->bigBlockSize;
+ }
+
+ /**
+ * Returns a stream for use with fread() etc. External callers should
+ * use OLE_PPS_File::getStream().
+ * @param int|PPS $blockIdOrPps block id or PPS
+ * @return resource read-only stream
+ */
+ function getStream($blockIdOrPps)
+ {
+ include_once 'OLE/ChainedBlockStream.php';
+ static $isRegistered = false;
+ if (!$isRegistered) {
+ stream_wrapper_register('ole-chainedblockstream',
+ 'OLE_ChainedBlockStream');
+ $isRegistered = true;
+ }
+
+ // Store current instance in global array, so that it can be accessed
+ // in OLE_ChainedBlockStream::stream_open().
+ // Object is removed from self::$instances in OLE_Stream::close().
+ $GLOBALS['_OLE_INSTANCES'][] = $this;
+ $instanceId = end(array_keys($GLOBALS['_OLE_INSTANCES']));
+
+ $path = 'ole-chainedblockstream://oleInstanceId=' . $instanceId;
+ if (is_a($blockIdOrPps, 'OLE_PPS')) {
+ $path .= '&blockId=' . $blockIdOrPps->_StartBlock;
+ $path .= '&size=' . $blockIdOrPps->Size;
+ } else {
+ $path .= '&blockId=' . $blockIdOrPps;
+ }
+ return fopen($path, 'r');
+ }
+
+ /**
+ * Reads a signed char.
+ * @param resource $fh file handle
+ * @return int
+ * @access private
+ */
+ function _readInt1($fh)
+ {
+ list(, $tmp) = unpack("c", fread($fh, 1));
+ return $tmp;
+ }
+
+ /**
+ * Reads an unsigned short (2 octets).
+ * @param resource $fh file handle
+ * @return int
+ * @access private
+ */
+ function _readInt2($fh)
+ {
+ list(, $tmp) = unpack("v", fread($fh, 2));
+ return $tmp;
+ }
+
+ /**
+ * Reads an unsigned long (4 octets).
+ * @param resource file handle
+ * @return int
+ * @access private
+ */
+ function _readInt4($fh)
+ {
+ list(, $tmp) = unpack("V", fread($fh, 4));
+ return $tmp;
+ }
+
+ /**
+ * Gets information about all PPS's on the OLE container from the PPS WK's
+ * creates an OLE_PPS object for each one.
+ *
+ * @access private
+ * @param integer $blockId the block id of the first block
+ * @return mixed true on success, PEAR_Error on failure
+ */
+ function _readPpsWks($blockId)
+ {
+ $fh = $this->getStream($blockId);
+ for ($pos = 0; ; $pos += 128) {
+ fseek($fh, $pos, SEEK_SET);
+ $nameUtf16 = fread($fh, 64);
+ $nameLength = $this->_readInt2($fh);
+ $nameUtf16 = substr($nameUtf16, 0, $nameLength - 2);
+ // Simple conversion from UTF-16LE to ISO-8859-1
+ $name = str_replace("\x00", "", $nameUtf16);
+ $type = $this->_readInt1($fh);
+ switch ($type) {
+ case OLE_PPS_TYPE_ROOT:
+ require_once 'OLE/PPS/Root.php';
+ $pps = new OLE_PPS_Root(null, null, array());
+ $this->root = $pps;
+ break;
+ case OLE_PPS_TYPE_DIR:
+ $pps = new OLE_PPS(null, null, null, null, null,
+ null, null, null, null, array());
+ break;
+ case OLE_PPS_TYPE_FILE:
+ require_once 'OLE/PPS/File.php';
+ $pps = new OLE_PPS_File($name);
+ break;
+ default:
+ continue;
+ }
+ fseek($fh, 1, SEEK_CUR);
+ $pps->Type = $type;
+ $pps->Name = $name;
+ $pps->PrevPps = $this->_readInt4($fh);
+ $pps->NextPps = $this->_readInt4($fh);
+ $pps->DirPps = $this->_readInt4($fh);
+ fseek($fh, 20, SEEK_CUR);
+ $pps->Time1st = OLE::OLE2LocalDate(fread($fh, 8));
+ $pps->Time2nd = OLE::OLE2LocalDate(fread($fh, 8));
+ $pps->_StartBlock = $this->_readInt4($fh);
+ $pps->Size = $this->_readInt4($fh);
+ $pps->No = count($this->_list);
+ $this->_list[] = $pps;
+
+ // check if the PPS tree (starting from root) is complete
+ if (isset($this->root) &&
+ $this->_ppsTreeComplete($this->root->No)) {
+
+ break;
+ }
+ }
+ fclose($fh);
+
+ // Initialize $pps->children on directories
+ foreach ($this->_list as $pps) {
+ if ($pps->Type == OLE_PPS_TYPE_DIR || $pps->Type == OLE_PPS_TYPE_ROOT) {
+ $nos = array($pps->DirPps);
+ $pps->children = array();
+ while ($nos) {
+ $no = array_pop($nos);
+ if ($no != -1) {
+ $childPps = $this->_list[$no];
+ $nos[] = $childPps->PrevPps;
+ $nos[] = $childPps->NextPps;
+ $pps->children[] = $childPps;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * It checks whether the PPS tree is complete (all PPS's read)
+ * starting with the given PPS (not necessarily root)
+ *
+ * @access private
+ * @param integer $index The index of the PPS from which we are checking
+ * @return boolean Whether the PPS tree for the given PPS is complete
+ */
+ function _ppsTreeComplete($index)
+ {
+ return isset($this->_list[$index]) &&
+ ($pps = $this->_list[$index]) &&
+ ($pps->PrevPps == -1 ||
+ $this->_ppsTreeComplete($pps->PrevPps)) &&
+ ($pps->NextPps == -1 ||
+ $this->_ppsTreeComplete($pps->NextPps)) &&
+ ($pps->DirPps == -1 ||
+ $this->_ppsTreeComplete($pps->DirPps));
+ }
+
+ /**
+ * Checks whether a PPS is a File PPS or not.
+ * If there is no PPS for the index given, it will return false.
+ * @param integer $index The index for the PPS
+ * @return bool true if it's a File PPS, false otherwise
+ * @access public
+ */
+ function isFile($index)
+ {
+ if (isset($this->_list[$index])) {
+ return ($this->_list[$index]->Type == OLE_PPS_TYPE_FILE);
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether a PPS is a Root PPS or not.
+ * If there is no PPS for the index given, it will return false.
+ * @param integer $index The index for the PPS.
+ * @return bool true if it's a Root PPS, false otherwise
+ * @access public
+ */
+ function isRoot($index)
+ {
+ if (isset($this->_list[$index])) {
+ return ($this->_list[$index]->Type == OLE_PPS_TYPE_ROOT);
+ }
+ return false;
+ }
+
+ /**
+ * Gives the total number of PPS's found in the OLE container.
+ * @return integer The total number of PPS's found in the OLE container
+ * @access public
+ */
+ function ppsTotal()
+ {
+ return count($this->_list);
+ }
+
+ /**
+ * Gets data from a PPS
+ * If there is no PPS for the index given, it will return an empty string.
+ * @param integer $index The index for the PPS
+ * @param integer $position The position from which to start reading
+ * (relative to the PPS)
+ * @param integer $length The amount of bytes to read (at most)
+ * @return string The binary string containing the data requested
+ * @access public
+ * @see OLE_PPS_File::getStream()
+ */
+ function getData($index, $position, $length)
+ {
+ // if position is not valid return empty string
+ if (!isset($this->_list[$index]) ||
+ $position >= $this->_list[$index]->Size ||
+ $position < 0) {
+
+ return '';
+ }
+ $fh = $this->getStream($this->_list[$index]);
+ $data = stream_get_contents($fh, $length, $position);
+ fclose($fh);
+ return $data;
+ }
+
+ /**
+ * Gets the data length from a PPS
+ * If there is no PPS for the index given, it will return 0.
+ * @param integer $index The index for the PPS
+ * @return integer The amount of bytes in data the PPS has
+ * @access public
+ */
+ function getDataLength($index)
+ {
+ if (isset($this->_list[$index])) {
+ return $this->_list[$index]->Size;
+ }
+ return 0;
+ }
+
+ /**
+ * Utility function to transform ASCII text to Unicode
+ *
+ * @access public
+ * @static
+ * @param string $ascii The ASCII string to transform
+ * @return string The string in Unicode
+ */
+ static function Asc2Ucs($ascii)
+ {
+ $rawname = '';
+ for ($i = 0; $i < strlen($ascii); $i++) {
+ $rawname .= $ascii{$i} . "\x00";
+ }
+ return $rawname;
+ }
+
+ /**
+ * Utility function
+ * Returns a string for the OLE container with the date given
+ *
+ * @access public
+ * @static
+ * @param integer $date A timestamp
+ * @return string The string for the OLE container
+ */
+ static function LocalDate2OLE($date = null)
+ {
+ if (!isset($date)) {
+ return "\x00\x00\x00\x00\x00\x00\x00\x00";
+ }
+
+ // factor used for separating numbers into 4 bytes parts
+ $factor = pow(2, 32);
+
+ // days from 1-1-1601 until the beggining of UNIX era
+ $days = 134774;
+ // calculate seconds
+ $big_date = $days * 24 * 3600 +
+ gmmktime(date("H",$date),date("i",$date),date("s",$date),
+ date("m",$date),date("d",$date),date("Y",$date));
+ // multiply just to make MS happy
+ $big_date *= 10000000;
+
+ $high_part = floor($big_date / $factor);
+ // lower 4 bytes
+ $low_part = floor((($big_date / $factor) - $high_part) * $factor);
+
+ // Make HEX string
+ $res = '';
+
+ for ($i = 0; $i < 4; $i++) {
+ $hex = $low_part % 0x100;
+ $res .= pack('c', $hex);
+ $low_part /= 0x100;
+ }
+ for ($i = 0; $i < 4; $i++) {
+ $hex = $high_part % 0x100;
+ $res .= pack('c', $hex);
+ $high_part /= 0x100;
+ }
+ return $res;
+ }
+
+ /**
+ * Returns a timestamp from an OLE container's date
+ * @param integer $string A binary string with the encoded date
+ * @return string The timestamp corresponding to the string
+ * @access public
+ * @static
+ */
+ static function OLE2LocalDate($string)
+ {
+ if (strlen($string) != 8) {
+ return new PEAR_Error("Expecting 8 byte string");
+ }
+
+ // factor used for separating numbers into 4 bytes parts
+ $factor = pow(2,32);
+ $high_part = 0;
+ for ($i = 0; $i < 4; $i++) {
+ list(, $high_part) = unpack('C', $string{(7 - $i)});
+ if ($i < 3) {
+ $high_part *= 0x100;
+ }
+ }
+ $low_part = 0;
+ for ($i = 4; $i < 8; $i++) {
+ list(, $low_part) = unpack('C', $string{(7 - $i)});
+ if ($i < 7) {
+ $low_part *= 0x100;
+ }
+ }
+ $big_date = ($high_part * $factor) + $low_part;
+ // translate to seconds
+ $big_date /= 10000000;
+
+ // days from 1-1-1601 until the beggining of UNIX era
+ $days = 134774;
+
+ // translate to seconds from beggining of UNIX era
+ $big_date -= $days * 24 * 3600;
+ return floor($big_date);
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/OLE/PPS.php b/vendor/library/Excel/phpxls/OLE/PPS.php
new file mode 100644
index 0000000..d3082d6
--- /dev/null
+++ b/vendor/library/Excel/phpxls/OLE/PPS.php
@@ -0,0 +1,224 @@
+ |
+// | Based on OLE::Storage_Lite by Kawai, Takanori |
+// +----------------------------------------------------------------------+
+//
+// $Id: PPS.php,v 1.7 2007/02/13 21:00:42 schmidt Exp $
+
+
+require_once 'PEAR.php';
+require_once 'OLE.php';
+
+/**
+* Class for creating PPS's for OLE containers
+*
+* @author Xavier Noguer
+* @category Structures
+* @package OLE
+*/
+class OLE_PPS extends PEAR
+{
+ /**
+ * The PPS index
+ * @var integer
+ */
+ var $No;
+
+ /**
+ * The PPS name (in Unicode)
+ * @var string
+ */
+ var $Name;
+
+ /**
+ * The PPS type. Dir, Root or File
+ * @var integer
+ */
+ var $Type;
+
+ /**
+ * The index of the previous PPS
+ * @var integer
+ */
+ var $PrevPps;
+
+ /**
+ * The index of the next PPS
+ * @var integer
+ */
+ var $NextPps;
+
+ /**
+ * The index of it's first child if this is a Dir or Root PPS
+ * @var integer
+ */
+ var $DirPps;
+
+ /**
+ * A timestamp
+ * @var integer
+ */
+ var $Time1st;
+
+ /**
+ * A timestamp
+ * @var integer
+ */
+ var $Time2nd;
+
+ /**
+ * Starting block (small or big) for this PPS's data inside the container
+ * @var integer
+ */
+ var $_StartBlock;
+
+ /**
+ * The size of the PPS's data (in bytes)
+ * @var integer
+ */
+ var $Size;
+
+ /**
+ * The PPS's data (only used if it's not using a temporary file)
+ * @var string
+ */
+ var $_data;
+
+ /**
+ * Array of child PPS's (only used by Root and Dir PPS's)
+ * @var array
+ */
+ var $children = array();
+
+ /**
+ * Pointer to OLE container
+ * @var OLE
+ */
+ var $ole;
+
+ /**
+ * The constructor
+ *
+ * @access public
+ * @param integer $No The PPS index
+ * @param string $name The PPS name
+ * @param integer $type The PPS type. Dir, Root or File
+ * @param integer $prev The index of the previous PPS
+ * @param integer $next The index of the next PPS
+ * @param integer $dir The index of it's first child if this is a Dir or Root PPS
+ * @param integer $time_1st A timestamp
+ * @param integer $time_2nd A timestamp
+ * @param string $data The (usually binary) source data of the PPS
+ * @param array $children Array containing children PPS for this PPS
+ */
+ function __construct(){}
+
+ function OLE_PPS($No, $name, $type, $prev, $next, $dir, $time_1st, $time_2nd, $data, $children)
+ {
+ $this->No = $No;
+ $this->Name = $name;
+ $this->Type = $type;
+ $this->PrevPps = $prev;
+ $this->NextPps = $next;
+ $this->DirPps = $dir;
+ $this->Time1st = $time_1st;
+ $this->Time2nd = $time_2nd;
+ $this->_data = $data;
+ $this->children = $children;
+ if ($data != '') {
+ $this->Size = strlen($data);
+ } else {
+ $this->Size = 0;
+ }
+ }
+
+ /**
+ * Returns the amount of data saved for this PPS
+ *
+ * @access private
+ * @return integer The amount of data (in bytes)
+ */
+ function _DataLen()
+ {
+ if (!isset($this->_data)) {
+ return 0;
+ }
+ if (isset($this->_PPS_FILE)) {
+ fseek($this->_PPS_FILE, 0);
+ $stats = fstat($this->_PPS_FILE);
+ return $stats[7];
+ } else {
+ return strlen($this->_data);
+ }
+ }
+
+ /**
+ * Returns a string with the PPS's WK (What is a WK?)
+ *
+ * @access private
+ * @return string The binary string
+ */
+ function _getPpsWk()
+ {
+ $ret = $this->Name;
+ for ($i = 0; $i < (64 - strlen($this->Name)); $i++) {
+ $ret .= "\x00";
+ }
+ $ret .= pack("v", strlen($this->Name) + 2) // 66
+ . pack("c", $this->Type) // 67
+ . pack("c", 0x00) //UK // 68
+ . pack("V", $this->PrevPps) //Prev // 72
+ . pack("V", $this->NextPps) //Next // 76
+ . pack("V", $this->DirPps) //Dir // 80
+ . "\x00\x09\x02\x00" // 84
+ . "\x00\x00\x00\x00" // 88
+ . "\xc0\x00\x00\x00" // 92
+ . "\x00\x00\x00\x46" // 96 // Seems to be ok only for Root
+ . "\x00\x00\x00\x00" // 100
+ . OLE::LocalDate2OLE($this->Time1st) // 108
+ . OLE::LocalDate2OLE($this->Time2nd) // 116
+ . pack("V", isset($this->_StartBlock)?
+ $this->_StartBlock:0) // 120
+ . pack("V", $this->Size) // 124
+ . pack("V", 0); // 128
+ return $ret;
+ }
+
+ /**
+ * Updates index and pointers to previous, next and children PPS's for this
+ * PPS. I don't think it'll work with Dir PPS's.
+ *
+ * @access private
+ * @param array &$pps_array Reference to the array of PPS's for the whole OLE
+ * container
+ * @return integer The index for this PPS
+ */
+ function _savePpsSetPnt(&$pps_array)
+ {
+ $pps_array[count($pps_array)] = &$this;
+ $this->No = count($pps_array) - 1;
+ $this->PrevPps = 0xFFFFFFFF;
+ $this->NextPps = 0xFFFFFFFF;
+ if (count($this->children) > 0) {
+ $this->DirPps = $this->children[0]->_savePpsSetPnt($pps_array);
+ } else {
+ $this->DirPps = 0xFFFFFFFF;
+ }
+ return $this->No;
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/OLE/PPS/File.php b/vendor/library/Excel/phpxls/OLE/PPS/File.php
new file mode 100644
index 0000000..3f48646
--- /dev/null
+++ b/vendor/library/Excel/phpxls/OLE/PPS/File.php
@@ -0,0 +1,125 @@
+ |
+// | Based on OLE::Storage_Lite by Kawai, Takanori |
+// +----------------------------------------------------------------------+
+//
+// $Id: File.php,v 1.12 2008/02/02 21:00:37 schmidt Exp $
+
+
+require_once 'OLE/PPS.php';
+require_once 'System.php';
+
+/**
+* Class for creating File PPS's for OLE containers
+*
+* @author Xavier Noguer
+* @category Structures
+* @package OLE
+*/
+class OLE_PPS_File extends OLE_PPS
+{
+ /**
+ * The temporary dir for storing the OLE file
+ * @var string
+ */
+ var $_tmp_dir;
+
+ /**
+ * The constructor
+ *
+ * @access public
+ * @param string $name The name of the file (in Unicode)
+ * @see OLE::Asc2Ucs()
+ */
+ function __construct($name)
+ {
+ $this->_tmp_dir = System::tmpdir();
+ $this->OLE_PPS(
+ null,
+ $name,
+ OLE_PPS_TYPE_FILE,
+ null,
+ null,
+ null,
+ null,
+ null,
+ '',
+ array());
+ }
+
+ /**
+ * Sets the temp dir used for storing the OLE file
+ *
+ * @access public
+ * @param string $dir The dir to be used as temp dir
+ * @return true if given dir is valid, false otherwise
+ */
+ function setTempDir($dir)
+ {
+ if (is_dir($dir)) {
+ $this->_tmp_dir = $dir;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Initialization method. Has to be called right after OLE_PPS_File().
+ *
+ * @access public
+ * @return mixed true on success. PEAR_Error on failure
+ */
+ function init()
+ {
+ $this->_tmp_filename = tempnam($this->_tmp_dir, "OLE_PPS_File");
+ $fh = @fopen($this->_tmp_filename, "w+b");
+ if ($fh == false) {
+ return $this->raiseError("Can't create temporary file");
+ }
+ $this->_PPS_FILE = $fh;
+ if ($this->_PPS_FILE) {
+ fseek($this->_PPS_FILE, 0);
+ }
+
+ return true;
+ }
+
+ /**
+ * Append data to PPS
+ *
+ * @access public
+ * @param string $data The data to append
+ */
+ function append($data)
+ {
+ if ($this->_PPS_FILE) {
+ fwrite($this->_PPS_FILE, $data);
+ } else {
+ $this->_data .= $data;
+ }
+ }
+
+ /**
+ * Returns a stream for reading this file using fread() etc.
+ * @return resource a read-only stream
+ */
+ function getStream()
+ {
+ $this->ole->getStream($this);
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/OLE/PPS/Root.php b/vendor/library/Excel/phpxls/OLE/PPS/Root.php
new file mode 100644
index 0000000..95ff809
--- /dev/null
+++ b/vendor/library/Excel/phpxls/OLE/PPS/Root.php
@@ -0,0 +1,486 @@
+ |
+// | Based on OLE::Storage_Lite by Kawai, Takanori |
+// +----------------------------------------------------------------------+
+//
+// $Id: Root.php,v 1.10 2008/02/02 21:00:37 schmidt Exp $
+
+
+require_once 'OLE/PPS.php';
+require_once 'System.php';
+
+/**
+* Class for creating Root PPS's for OLE containers
+*
+* @author Xavier Noguer
+* @category Structures
+* @package OLE
+*/
+class OLE_PPS_Root extends OLE_PPS
+{
+ /**
+ * The temporary dir for storing the OLE file
+ * @var string
+ */
+ var $_tmp_dir;
+
+ /**
+ * Constructor
+ *
+ * @access public
+ * @param integer $time_1st A timestamp
+ * @param integer $time_2nd A timestamp
+ */
+ function __construct($time_1st, $time_2nd, $raChild)
+ {
+ $this->_tmp_dir = System::tmpdir();
+ $this->OLE_PPS(
+ null,
+ OLE::Asc2Ucs('Root Entry'),
+ OLE_PPS_TYPE_ROOT,
+ null,
+ null,
+ null,
+ $time_1st,
+ $time_2nd,
+ null,
+ $raChild);
+ }
+
+ /**
+ * Sets the temp dir used for storing the OLE file
+ *
+ * @access public
+ * @param string $dir The dir to be used as temp dir
+ * @return true if given dir is valid, false otherwise
+ */
+ function setTempDir($dir)
+ {
+ if (is_dir($dir)) {
+ $this->_tmp_dir = $dir;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Method for saving the whole OLE container (including files).
+ * In fact, if called with an empty argument (or '-'), it saves to a
+ * temporary file and then outputs it's contents to stdout.
+ *
+ * @param string $filename The name of the file where to save the OLE container
+ * @access public
+ * @return mixed true on success, PEAR_Error on failure
+ */
+ function save($filename)
+ {
+ // Initial Setting for saving
+ $this->_BIG_BLOCK_SIZE = pow(2,
+ ((isset($this->_BIG_BLOCK_SIZE))? $this->_adjust2($this->_BIG_BLOCK_SIZE) : 9));
+ $this->_SMALL_BLOCK_SIZE= pow(2,
+ ((isset($this->_SMALL_BLOCK_SIZE))? $this->_adjust2($this->_SMALL_BLOCK_SIZE): 6));
+
+ // Open temp file if we are sending output to stdout
+ if (($filename == '-') || ($filename == '')) {
+ $this->_tmp_filename = tempnam($this->_tmp_dir, "OLE_PPS_Root");
+ $this->_FILEH_ = @fopen($this->_tmp_filename,"w+b");
+ if ($this->_FILEH_ == false) {
+ return $this->raiseError("Can't create temporary file.");
+ }
+ } else {
+ $this->_FILEH_ = @fopen($filename, "wb");
+ if ($this->_FILEH_ == false) {
+ return $this->raiseError("Can't open $filename. It may be in use or protected.");
+ }
+ }
+ // Make an array of PPS's (for Save)
+ $aList = array();
+ $this->_savePpsSetPnt($aList);
+ // calculate values for header
+ list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList); //, $rhInfo);
+ // Save Header
+ $this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt);
+
+ // Make Small Data string (write SBD)
+ $this->_data = $this->_makeSmallData($aList);
+
+ // Write BB
+ $this->_saveBigData($iSBDcnt, $aList);
+ // Write PPS
+ $this->_savePps($aList);
+ // Write Big Block Depot and BDList and Adding Header informations
+ $this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt);
+ // Close File, send it to stdout if necessary
+ if (($filename == '-') || ($filename == '')) {
+ fseek($this->_FILEH_, 0);
+ fpassthru($this->_FILEH_);
+ @fclose($this->_FILEH_);
+ // Delete the temporary file.
+ @unlink($this->_tmp_filename);
+ } else {
+ @fclose($this->_FILEH_);
+ }
+
+ return true;
+ }
+
+ /**
+ * Calculate some numbers
+ *
+ * @access private
+ * @param array $raList Reference to an array of PPS's
+ * @return array The array of numbers
+ */
+ function _calcSize(&$raList)
+ {
+ // Calculate Basic Setting
+ list($iSBDcnt, $iBBcnt, $iPPScnt) = array(0,0,0);
+ $iSmallLen = 0;
+ $iSBcnt = 0;
+ for ($i = 0; $i < count($raList); $i++) {
+ if ($raList[$i]->Type == OLE_PPS_TYPE_FILE) {
+ $raList[$i]->Size = $raList[$i]->_DataLen();
+ if ($raList[$i]->Size < OLE_DATA_SIZE_SMALL) {
+ $iSBcnt += floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE)
+ + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0);
+ } else {
+ $iBBcnt += (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) +
+ (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0));
+ }
+ }
+ }
+ $iSmallLen = $iSBcnt * $this->_SMALL_BLOCK_SIZE;
+ $iSlCnt = floor($this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE);
+ $iSBDcnt = floor($iSBcnt / $iSlCnt) + (($iSBcnt % $iSlCnt)? 1:0);
+ $iBBcnt += (floor($iSmallLen / $this->_BIG_BLOCK_SIZE) +
+ (( $iSmallLen % $this->_BIG_BLOCK_SIZE)? 1: 0));
+ $iCnt = count($raList);
+ $iBdCnt = $this->_BIG_BLOCK_SIZE / OLE_PPS_SIZE;
+ $iPPScnt = (floor($iCnt/$iBdCnt) + (($iCnt % $iBdCnt)? 1: 0));
+
+ return array($iSBDcnt, $iBBcnt, $iPPScnt);
+ }
+
+ /**
+ * Helper function for caculating a magic value for block sizes
+ *
+ * @access private
+ * @param integer $i2 The argument
+ * @see save()
+ * @return integer
+ */
+ function _adjust2($i2)
+ {
+ $iWk = log($i2)/log(2);
+ return ($iWk > floor($iWk))? floor($iWk)+1:$iWk;
+ }
+
+ /**
+ * Save OLE header
+ *
+ * @access private
+ * @param integer $iSBDcnt
+ * @param integer $iBBcnt
+ * @param integer $iPPScnt
+ */
+ function _saveHeader($iSBDcnt, $iBBcnt, $iPPScnt)
+ {
+ $FILE = $this->_FILEH_;
+
+ // Calculate Basic Setting
+ $iBlCnt = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE;
+ $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / OLE_LONG_INT_SIZE;
+
+ $iBdExL = 0;
+ $iAll = $iBBcnt + $iPPScnt + $iSBDcnt;
+ $iAllW = $iAll;
+ $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
+ $iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0);
+
+ // Calculate BD count
+ if ($iBdCnt > $i1stBdL) {
+ while (1) {
+ $iBdExL++;
+ $iAllW++;
+ $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
+ $iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0);
+ if ($iBdCnt <= ($iBdExL*$iBlCnt+ $i1stBdL)) {
+ break;
+ }
+ }
+ }
+
+ // Save Header
+ fwrite($FILE,
+ "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
+ . "\x00\x00\x00\x00"
+ . "\x00\x00\x00\x00"
+ . "\x00\x00\x00\x00"
+ . "\x00\x00\x00\x00"
+ . pack("v", 0x3b)
+ . pack("v", 0x03)
+ . pack("v", -2)
+ . pack("v", 9)
+ . pack("v", 6)
+ . pack("v", 0)
+ . "\x00\x00\x00\x00"
+ . "\x00\x00\x00\x00"
+ . pack("V", $iBdCnt)
+ . pack("V", $iBBcnt+$iSBDcnt) //ROOT START
+ . pack("V", 0)
+ . pack("V", 0x1000)
+ . pack("V", 0) //Small Block Depot
+ . pack("V", 1)
+ );
+ // Extra BDList Start, Count
+ if ($iBdCnt < $i1stBdL) {
+ fwrite($FILE,
+ pack("V", -2). // Extra BDList Start
+ pack("V", 0) // Extra BDList Count
+ );
+ } else {
+ fwrite($FILE, pack("V", $iAll+$iBdCnt) . pack("V", $iBdExL));
+ }
+
+ // BDList
+ for ($i = 0; $i < $i1stBdL && $i < $iBdCnt; $i++) {
+ fwrite($FILE, pack("V", $iAll+$i));
+ }
+ if ($i < $i1stBdL) {
+ for ($j = 0; $j < ($i1stBdL-$i); $j++) {
+ fwrite($FILE, (pack("V", -1)));
+ }
+ }
+ }
+
+ /**
+ * Saving big data (PPS's with data bigger than OLE_DATA_SIZE_SMALL)
+ *
+ * @access private
+ * @param integer $iStBlk
+ * @param array &$raList Reference to array of PPS's
+ */
+ function _saveBigData($iStBlk, &$raList)
+ {
+ $FILE = $this->_FILEH_;
+
+ // cycle through PPS's
+ for ($i = 0; $i < count($raList); $i++) {
+ if ($raList[$i]->Type != OLE_PPS_TYPE_DIR) {
+ $raList[$i]->Size = $raList[$i]->_DataLen();
+ if (($raList[$i]->Size >= OLE_DATA_SIZE_SMALL) ||
+ (($raList[$i]->Type == OLE_PPS_TYPE_ROOT) && isset($raList[$i]->_data)))
+ {
+ // Write Data
+ if (isset($raList[$i]->_PPS_FILE)) {
+ $iLen = 0;
+ fseek($raList[$i]->_PPS_FILE, 0); // To The Top
+ while($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) {
+ $iLen += strlen($sBuff);
+ fwrite($FILE, $sBuff);
+ }
+ } else {
+ fwrite($FILE, $raList[$i]->_data);
+ }
+
+ if ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE) {
+ for ($j = 0; $j < ($this->_BIG_BLOCK_SIZE - ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)); $j++) {
+ fwrite($FILE, "\x00");
+ }
+ }
+ // Set For PPS
+ $raList[$i]->_StartBlock = $iStBlk;
+ $iStBlk +=
+ (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) +
+ (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0));
+ }
+ // Close file for each PPS, and unlink it
+ if (isset($raList[$i]->_PPS_FILE)) {
+ @fclose($raList[$i]->_PPS_FILE);
+ $raList[$i]->_PPS_FILE = null;
+ @unlink($raList[$i]->_tmp_filename);
+ }
+ }
+ }
+ }
+
+ /**
+ * get small data (PPS's with data smaller than OLE_DATA_SIZE_SMALL)
+ *
+ * @access private
+ * @param array &$raList Reference to array of PPS's
+ */
+ function _makeSmallData(&$raList)
+ {
+ $sRes = '';
+ $FILE = $this->_FILEH_;
+ $iSmBlk = 0;
+
+ for ($i = 0; $i < count($raList); $i++) {
+ // Make SBD, small data string
+ if ($raList[$i]->Type == OLE_PPS_TYPE_FILE) {
+ if ($raList[$i]->Size <= 0) {
+ continue;
+ }
+ if ($raList[$i]->Size < OLE_DATA_SIZE_SMALL) {
+ $iSmbCnt = floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE)
+ + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0);
+ // Add to SBD
+ for ($j = 0; $j < ($iSmbCnt-1); $j++) {
+ fwrite($FILE, pack("V", $j+$iSmBlk+1));
+ }
+ fwrite($FILE, pack("V", -2));
+
+ // Add to Data String(this will be written for RootEntry)
+ if ($raList[$i]->_PPS_FILE) {
+ fseek($raList[$i]->_PPS_FILE, 0); // To The Top
+ while ($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) {
+ $sRes .= $sBuff;
+ }
+ } else {
+ $sRes .= $raList[$i]->_data;
+ }
+ if ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE) {
+ for ($j = 0; $j < ($this->_SMALL_BLOCK_SIZE - ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)); $j++) {
+ $sRes .= "\x00";
+ }
+ }
+ // Set for PPS
+ $raList[$i]->_StartBlock = $iSmBlk;
+ $iSmBlk += $iSmbCnt;
+ }
+ }
+ }
+ $iSbCnt = floor($this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE);
+ if ($iSmBlk % $iSbCnt) {
+ for ($i = 0; $i < ($iSbCnt - ($iSmBlk % $iSbCnt)); $i++) {
+ fwrite($FILE, pack("V", -1));
+ }
+ }
+ return $sRes;
+ }
+
+ /**
+ * Saves all the PPS's WKs
+ *
+ * @access private
+ * @param array $raList Reference to an array with all PPS's
+ */
+ function _savePps(&$raList)
+ {
+ // Save each PPS WK
+ for ($i = 0; $i < count($raList); $i++) {
+ fwrite($this->_FILEH_, $raList[$i]->_getPpsWk());
+ }
+ // Adjust for Block
+ $iCnt = count($raList);
+ $iBCnt = $this->_BIG_BLOCK_SIZE / OLE_PPS_SIZE;
+ if ($iCnt % $iBCnt) {
+ for ($i = 0; $i < (($iBCnt - ($iCnt % $iBCnt)) * OLE_PPS_SIZE); $i++) {
+ fwrite($this->_FILEH_, "\x00");
+ }
+ }
+ }
+
+ /**
+ * Saving Big Block Depot
+ *
+ * @access private
+ * @param integer $iSbdSize
+ * @param integer $iBsize
+ * @param integer $iPpsCnt
+ */
+ function _saveBbd($iSbdSize, $iBsize, $iPpsCnt)
+ {
+ $FILE = $this->_FILEH_;
+ // Calculate Basic Setting
+ $iBbCnt = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE;
+ $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / OLE_LONG_INT_SIZE;
+
+ $iBdExL = 0;
+ $iAll = $iBsize + $iPpsCnt + $iSbdSize;
+ $iAllW = $iAll;
+ $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
+ $iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0);
+ // Calculate BD count
+ if ($iBdCnt >$i1stBdL) {
+ while (1) {
+ $iBdExL++;
+ $iAllW++;
+ $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
+ $iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0);
+ if ($iBdCnt <= ($iBdExL*$iBbCnt+ $i1stBdL)) {
+ break;
+ }
+ }
+ }
+
+ // Making BD
+ // Set for SBD
+ if ($iSbdSize > 0) {
+ for ($i = 0; $i < ($iSbdSize - 1); $i++) {
+ fwrite($FILE, pack("V", $i+1));
+ }
+ fwrite($FILE, pack("V", -2));
+ }
+ // Set for B
+ for ($i = 0; $i < ($iBsize - 1); $i++) {
+ fwrite($FILE, pack("V", $i+$iSbdSize+1));
+ }
+ fwrite($FILE, pack("V", -2));
+
+ // Set for PPS
+ for ($i = 0; $i < ($iPpsCnt - 1); $i++) {
+ fwrite($FILE, pack("V", $i+$iSbdSize+$iBsize+1));
+ }
+ fwrite($FILE, pack("V", -2));
+ // Set for BBD itself ( 0xFFFFFFFD : BBD)
+ for ($i = 0; $i < $iBdCnt; $i++) {
+ fwrite($FILE, pack("V", 0xFFFFFFFD));
+ }
+ // Set for ExtraBDList
+ for ($i = 0; $i < $iBdExL; $i++) {
+ fwrite($FILE, pack("V", 0xFFFFFFFC));
+ }
+ // Adjust for Block
+ if (($iAllW + $iBdCnt) % $iBbCnt) {
+ for ($i = 0; $i < ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt)); $i++) {
+ fwrite($FILE, pack("V", -1));
+ }
+ }
+ // Extra BDList
+ if ($iBdCnt > $i1stBdL) {
+ $iN=0;
+ $iNb=0;
+ for ($i = $i1stBdL;$i < $iBdCnt; $i++, $iN++) {
+ if ($iN >= ($iBbCnt - 1)) {
+ $iN = 0;
+ $iNb++;
+ fwrite($FILE, pack("V", $iAll+$iBdCnt+$iNb));
+ }
+ fwrite($FILE, pack("V", $iBsize+$iSbdSize+$iPpsCnt+$i));
+ }
+ if (($iBdCnt-$i1stBdL) % ($iBbCnt-1)) {
+ for ($i = 0; $i < (($iBbCnt - 1) - (($iBdCnt - $i1stBdL) % ($iBbCnt - 1))); $i++) {
+ fwrite($FILE, pack("V", -1));
+ }
+ }
+ fwrite($FILE, pack("V", -2));
+ }
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/OS/Guess.php b/vendor/library/Excel/phpxls/OS/Guess.php
new file mode 100644
index 0000000..d266e70
--- /dev/null
+++ b/vendor/library/Excel/phpxls/OS/Guess.php
@@ -0,0 +1,344 @@
+
+ * @author Gregory Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Guess.php,v 1.26 2008/01/03 20:26:34 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since PEAR 0.1
+ */
+
+// {{{ uname examples
+
+// php_uname() without args returns the same as 'uname -a', or a PHP-custom
+// string for Windows.
+// PHP versions prior to 4.3 return the uname of the host where PHP was built,
+// as of 4.3 it returns the uname of the host running the PHP code.
+//
+// PC RedHat Linux 7.1:
+// Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown
+//
+// PC Debian Potato:
+// Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown
+//
+// PC FreeBSD 3.3:
+// FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000 root@example.com:/usr/src/sys/compile/CONFIG i386
+//
+// PC FreeBSD 4.3:
+// FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001 root@example.com:/usr/src/sys/compile/CONFIG i386
+//
+// PC FreeBSD 4.5:
+// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb 6 23:59:23 CET 2002 root@example.com:/usr/src/sys/compile/CONFIG i386
+//
+// PC FreeBSD 4.5 w/uname from GNU shellutils:
+// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb i386 unknown
+//
+// HP 9000/712 HP-UX 10:
+// HP-UX iq B.10.10 A 9000/712 2008429113 two-user license
+//
+// HP 9000/712 HP-UX 10 w/uname from GNU shellutils:
+// HP-UX host B.10.10 A 9000/712 unknown
+//
+// IBM RS6000/550 AIX 4.3:
+// AIX host 3 4 000003531C00
+//
+// AIX 4.3 w/uname from GNU shellutils:
+// AIX host 3 4 000003531C00 unknown
+//
+// SGI Onyx IRIX 6.5 w/uname from GNU shellutils:
+// IRIX64 host 6.5 01091820 IP19 mips
+//
+// SGI Onyx IRIX 6.5:
+// IRIX64 host 6.5 01091820 IP19
+//
+// SparcStation 20 Solaris 8 w/uname from GNU shellutils:
+// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc
+//
+// SparcStation 20 Solaris 8:
+// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20
+//
+// Mac OS X (Darwin)
+// Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug 5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC Power Macintosh
+//
+// Mac OS X early versions
+//
+
+// }}}
+
+/* TODO:
+ * - define endianness, to allow matchSignature("bigend") etc.
+ */
+
+/**
+ * Retrieves information about the current operating system
+ *
+ * This class uses php_uname() to grok information about the current OS
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Gregory Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class OS_Guess
+{
+ var $sysname;
+ var $nodename;
+ var $cpu;
+ var $release;
+ var $extra;
+
+ function OS_Guess($uname = null)
+ {
+ list($this->sysname,
+ $this->release,
+ $this->cpu,
+ $this->extra,
+ $this->nodename) = $this->parseSignature($uname);
+ }
+
+ function parseSignature($uname = null)
+ {
+ static $sysmap = array(
+ 'HP-UX' => 'hpux',
+ 'IRIX64' => 'irix',
+ );
+ static $cpumap = array(
+ 'i586' => 'i386',
+ 'i686' => 'i386',
+ 'ppc' => 'powerpc',
+ );
+ if ($uname === null) {
+ $uname = php_uname();
+ }
+ $parts = split('[[:space:]]+', trim($uname));
+ $n = count($parts);
+
+ $release = $machine = $cpu = '';
+ $sysname = $parts[0];
+ $nodename = $parts[1];
+ $cpu = $parts[$n-1];
+ $extra = '';
+ if ($cpu == 'unknown') {
+ $cpu = $parts[$n-2];
+ }
+
+ switch ($sysname) {
+ case 'AIX' :
+ $release = "$parts[3].$parts[2]";
+ break;
+ case 'Windows' :
+ switch ($parts[1]) {
+ case '95/98':
+ $release = '9x';
+ break;
+ default:
+ $release = $parts[1];
+ break;
+ }
+ $cpu = 'i386';
+ break;
+ case 'Linux' :
+ $extra = $this->_detectGlibcVersion();
+ // use only the first two digits from the kernel version
+ $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
+ break;
+ case 'Mac' :
+ $sysname = 'darwin';
+ $nodename = $parts[2];
+ $release = $parts[3];
+ if ($cpu == 'Macintosh') {
+ if ($parts[$n - 2] == 'Power') {
+ $cpu = 'powerpc';
+ }
+ }
+ break;
+ case 'Darwin' :
+ if ($cpu == 'Macintosh') {
+ if ($parts[$n - 2] == 'Power') {
+ $cpu = 'powerpc';
+ }
+ }
+ $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
+ break;
+ default:
+ $release = ereg_replace('-.*', '', $parts[2]);
+ break;
+ }
+
+
+ if (isset($sysmap[$sysname])) {
+ $sysname = $sysmap[$sysname];
+ } else {
+ $sysname = strtolower($sysname);
+ }
+ if (isset($cpumap[$cpu])) {
+ $cpu = $cpumap[$cpu];
+ }
+ return array($sysname, $release, $cpu, $extra, $nodename);
+ }
+
+ function _detectGlibcVersion()
+ {
+ static $glibc = false;
+ if ($glibc !== false) {
+ return $glibc; // no need to run this multiple times
+ }
+ $major = $minor = 0;
+ include_once "System.php";
+ // Use glibc's header file to
+ // get major and minor version number:
+ if (@file_exists('/usr/include/features.h') &&
+ @is_readable('/usr/include/features.h')) {
+ if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) {
+ $features_file = fopen('/usr/include/features.h', 'rb');
+ while (!feof($features_file)) {
+ $line = fgets($features_file, 8192);
+ if (!$line || (strpos($line, '#define') === false)) {
+ continue;
+ }
+ if (strpos($line, '__GLIBC__')) {
+ // major version number #define __GLIBC__ version
+ $line = preg_split('/\s+/', $line);
+ $glibc_major = trim($line[2]);
+ if (isset($glibc_minor)) {
+ break;
+ }
+ continue;
+ }
+ if (strpos($line, '__GLIBC_MINOR__')) {
+ // got the minor version number
+ // #define __GLIBC_MINOR__ version
+ $line = preg_split('/\s+/', $line);
+ $glibc_minor = trim($line[2]);
+ if (isset($glibc_major)) {
+ break;
+ }
+ continue;
+ }
+ }
+ fclose($features_file);
+ if (!isset($glibc_major) || !isset($glibc_minor)) {
+ return $glibc = '';
+ }
+ return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ;
+ } // no cpp
+ $tmpfile = System::mktemp("glibctest");
+ $fp = fopen($tmpfile, "w");
+ fwrite($fp, "#include \n__GLIBC__ __GLIBC_MINOR__\n");
+ fclose($fp);
+ $cpp = popen("/usr/bin/cpp $tmpfile", "r");
+ while ($line = fgets($cpp, 1024)) {
+ if ($line{0} == '#' || trim($line) == '') {
+ continue;
+ }
+ if (list($major, $minor) = explode(' ', trim($line))) {
+ break;
+ }
+ }
+ pclose($cpp);
+ unlink($tmpfile);
+ } // features.h
+ if (!($major && $minor) && @is_link('/lib/libc.so.6')) {
+ // Let's try reading the libc.so.6 symlink
+ if (ereg('^libc-(.*)\.so$', basename(readlink('/lib/libc.so.6')), $matches)) {
+ list($major, $minor) = explode('.', $matches[1]);
+ }
+ }
+ if (!($major && $minor)) {
+ return $glibc = '';
+ }
+ return $glibc = "glibc{$major}.{$minor}";
+ }
+
+ function getSignature()
+ {
+ if (empty($this->extra)) {
+ return "{$this->sysname}-{$this->release}-{$this->cpu}";
+ }
+ return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}";
+ }
+
+ function getSysname()
+ {
+ return $this->sysname;
+ }
+
+ function getNodename()
+ {
+ return $this->nodename;
+ }
+
+ function getCpu()
+ {
+ return $this->cpu;
+ }
+
+ function getRelease()
+ {
+ return $this->release;
+ }
+
+ function getExtra()
+ {
+ return $this->extra;
+ }
+
+ function matchSignature($match)
+ {
+ if (is_array($match)) {
+ $fragments = $match;
+ } else {
+ $fragments = explode('-', $match);
+ }
+ $n = count($fragments);
+ $matches = 0;
+ if ($n > 0) {
+ $matches += $this->_matchFragment($fragments[0], $this->sysname);
+ }
+ if ($n > 1) {
+ $matches += $this->_matchFragment($fragments[1], $this->release);
+ }
+ if ($n > 2) {
+ $matches += $this->_matchFragment($fragments[2], $this->cpu);
+ }
+ if ($n > 3) {
+ $matches += $this->_matchFragment($fragments[3], $this->extra);
+ }
+ return ($matches == $n);
+ }
+
+ function _matchFragment($fragment, $value)
+ {
+ if (strcspn($fragment, '*?') < strlen($fragment)) {
+ $reg = '^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '$';
+ return eregi($reg, $value);
+ }
+ return ($fragment == '*' || !strcasecmp($fragment, $value));
+ }
+
+}
+/*
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * c-basic-offset: 4
+ * End:
+ */
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR.php b/vendor/library/Excel/phpxls/PEAR.php
new file mode 100644
index 0000000..2407533
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR.php
@@ -0,0 +1,1120 @@
+
+ * @author Stig Bakken
+ * @author Tomas V.V.Cox
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: PEAR.php,v 1.104 2008/01/03 20:26:34 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**#@+
+ * ERROR constants
+ */
+define('PEAR_ERROR_RETURN', 1);
+define('PEAR_ERROR_PRINT', 2);
+define('PEAR_ERROR_TRIGGER', 4);
+define('PEAR_ERROR_DIE', 8);
+define('PEAR_ERROR_CALLBACK', 16);
+/**
+ * WARNING: obsolete
+ * @deprecated
+ */
+define('PEAR_ERROR_EXCEPTION', 32);
+/**#@-*/
+define('PEAR_ZE2', (function_exists('version_compare') &&
+ version_compare(zend_version(), "2-dev", "ge")));
+
+if (substr(PHP_OS, 0, 3) == 'WIN') {
+ define('OS_WINDOWS', true);
+ define('OS_UNIX', false);
+ define('PEAR_OS', 'Windows');
+} else {
+ define('OS_WINDOWS', false);
+ define('OS_UNIX', true);
+ define('PEAR_OS', 'Unix'); // blatant assumption
+}
+
+// instant backwards compatibility
+if (!defined('PATH_SEPARATOR')) {
+ if (OS_WINDOWS) {
+ define('PATH_SEPARATOR', ';');
+ } else {
+ define('PATH_SEPARATOR', ':');
+ }
+}
+
+$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN;
+$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE;
+$GLOBALS['_PEAR_destructor_object_list'] = array();
+$GLOBALS['_PEAR_shutdown_funcs'] = array();
+$GLOBALS['_PEAR_error_handler_stack'] = array();
+
+@ini_set('track_errors', true);
+
+/**
+ * Base class for other PEAR classes. Provides rudimentary
+ * emulation of destructors.
+ *
+ * If you want a destructor in your class, inherit PEAR and make a
+ * destructor method called _yourclassname (same name as the
+ * constructor, but with a "_" prefix). Also, in your constructor you
+ * have to call the PEAR constructor: $this->PEAR();.
+ * The destructor method will be called without parameters. Note that
+ * at in some SAPI implementations (such as Apache), any output during
+ * the request shutdown (in which destructors are called) seems to be
+ * discarded. If you need to get any debug information from your
+ * destructor, use error_log(), syslog() or something similar.
+ *
+ * IMPORTANT! To use the emulated destructors you need to create the
+ * objects by reference: $obj =& new PEAR_child;
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Tomas V.V. Cox
+ * @author Greg Beaver
+ * @copyright 1997-2006 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @see PEAR_Error
+ * @since Class available since PHP 4.0.2
+ * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear
+ */
+class PEAR
+{
+ // {{{ properties
+
+ /**
+ * Whether to enable internal debug messages.
+ *
+ * @var bool
+ * @access private
+ */
+ var $_debug = false;
+
+ /**
+ * Default error mode for this object.
+ *
+ * @var int
+ * @access private
+ */
+ var $_default_error_mode = null;
+
+ /**
+ * Default error options used for this object when error mode
+ * is PEAR_ERROR_TRIGGER.
+ *
+ * @var int
+ * @access private
+ */
+ var $_default_error_options = null;
+
+ /**
+ * Default error handler (callback) for this object, if error mode is
+ * PEAR_ERROR_CALLBACK.
+ *
+ * @var string
+ * @access private
+ */
+ var $_default_error_handler = '';
+
+ /**
+ * Which class to use for error objects.
+ *
+ * @var string
+ * @access private
+ */
+ var $_error_class = 'PEAR_Error';
+
+ /**
+ * An array of expected errors.
+ *
+ * @var array
+ * @access private
+ */
+ var $_expected_errors = array();
+
+ // }}}
+
+ // {{{ constructor
+
+ /**
+ * Constructor. Registers this object in
+ * $_PEAR_destructor_object_list for destructor emulation if a
+ * destructor object exists.
+ *
+ * @param string $error_class (optional) which class to use for
+ * error objects, defaults to PEAR_Error.
+ * @access public
+ * @return void
+ */
+ function __construct($error_class = null)
+ {
+ $classname = strtolower(get_class($this));
+ if ($this->_debug) {
+ print "PEAR constructor called, class=$classname\n";
+ }
+ if ($error_class !== null) {
+ $this->_error_class = $error_class;
+ }
+ while ($classname && strcasecmp($classname, "pear")) {
+ $destructor = "_$classname";
+ if (method_exists($this, $destructor)) {
+ global $_PEAR_destructor_object_list;
+ $_PEAR_destructor_object_list[] = &$this;
+ if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
+ register_shutdown_function("_PEAR_call_destructors");
+ $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
+ }
+ break;
+ } else {
+ $classname = get_parent_class($classname);
+ }
+ }
+ }
+
+ // }}}
+ // {{{ destructor
+
+ /**
+ * Destructor (the emulated type of...). Does nothing right now,
+ * but is included for forward compatibility, so subclass
+ * destructors should always call it.
+ *
+ * See the note in the class desciption about output from
+ * destructors.
+ *
+ * @access public
+ * @return void
+ */
+ function _PEAR() {
+ if ($this->_debug) {
+ printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
+ }
+ }
+
+ // }}}
+ // {{{ getStaticProperty()
+
+ /**
+ * If you have a class that's mostly/entirely static, and you need static
+ * properties, you can use this method to simulate them. Eg. in your method(s)
+ * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
+ * You MUST use a reference, or they will not persist!
+ *
+ * @access public
+ * @param string $class The calling classname, to prevent clashes
+ * @param string $var The variable to retrieve.
+ * @return mixed A reference to the variable. If not set it will be
+ * auto initialised to NULL.
+ */
+ function &getStaticProperty($class, $var)
+ {
+ static $properties;
+ if (!isset($properties[$class])) {
+ $properties[$class] = array();
+ }
+ if (!array_key_exists($var, $properties[$class])) {
+ $properties[$class][$var] = null;
+ }
+ return $properties[$class][$var];
+ }
+
+ // }}}
+ // {{{ registerShutdownFunc()
+
+ /**
+ * Use this function to register a shutdown method for static
+ * classes.
+ *
+ * @access public
+ * @param mixed $func The function name (or array of class/method) to call
+ * @param mixed $args The arguments to pass to the function
+ * @return void
+ */
+ function registerShutdownFunc($func, $args = array())
+ {
+ // if we are called statically, there is a potential
+ // that no shutdown func is registered. Bug #6445
+ if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
+ register_shutdown_function("_PEAR_call_destructors");
+ $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
+ }
+ $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
+ }
+
+ // }}}
+ // {{{ isError()
+
+ /**
+ * Tell whether a value is a PEAR error.
+ *
+ * @param mixed $data the value to test
+ * @param int $code if $data is an error object, return true
+ * only if $code is a string and
+ * $obj->getMessage() == $code or
+ * $code is an integer and $obj->getCode() == $code
+ * @access public
+ * @return bool true if parameter is an error
+ */
+ function isError($data, $code = null)
+ {
+ if ($data instanceof PEAR_Error) {
+ if (is_null($code)) {
+ return true;
+ } elseif (is_string($code)) {
+ return $data->getMessage() == $code;
+ } else {
+ return $data->getCode() == $code;
+ }
+ }
+ return false;
+ }
+
+ // }}}
+ // {{{ setErrorHandling()
+
+ /**
+ * Sets how errors generated by this object should be handled.
+ * Can be invoked both in objects and statically. If called
+ * statically, setErrorHandling sets the default behaviour for all
+ * PEAR objects. If called in an object, setErrorHandling sets
+ * the default behaviour for that object.
+ *
+ * @param int $mode
+ * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
+ * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
+ * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
+ *
+ * @param mixed $options
+ * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
+ * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
+ *
+ * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
+ * to be the callback function or method. A callback
+ * function is a string with the name of the function, a
+ * callback method is an array of two elements: the element
+ * at index 0 is the object, and the element at index 1 is
+ * the name of the method to call in the object.
+ *
+ * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
+ * a printf format string used when printing the error
+ * message.
+ *
+ * @access public
+ * @return void
+ * @see PEAR_ERROR_RETURN
+ * @see PEAR_ERROR_PRINT
+ * @see PEAR_ERROR_TRIGGER
+ * @see PEAR_ERROR_DIE
+ * @see PEAR_ERROR_CALLBACK
+ * @see PEAR_ERROR_EXCEPTION
+ *
+ * @since PHP 4.0.5
+ */
+
+ function setErrorHandling($mode = null, $options = null)
+ {
+ if (isset($this) && ($this instanceof PEAR)) {
+ $setmode = &$this->_default_error_mode;
+ $setoptions = &$this->_default_error_options;
+ } else {
+ $setmode = &$GLOBALS['_PEAR_default_error_mode'];
+ $setoptions = &$GLOBALS['_PEAR_default_error_options'];
+ }
+
+ switch ($mode) {
+ case PEAR_ERROR_EXCEPTION:
+ case PEAR_ERROR_RETURN:
+ case PEAR_ERROR_PRINT:
+ case PEAR_ERROR_TRIGGER:
+ case PEAR_ERROR_DIE:
+ case null:
+ $setmode = $mode;
+ $setoptions = $options;
+ break;
+
+ case PEAR_ERROR_CALLBACK:
+ $setmode = $mode;
+ // class/object method callback
+ if (is_callable($options)) {
+ $setoptions = $options;
+ } else {
+ trigger_error("invalid error callback", E_USER_WARNING);
+ }
+ break;
+
+ default:
+ trigger_error("invalid error mode", E_USER_WARNING);
+ break;
+ }
+ }
+
+ // }}}
+ // {{{ expectError()
+
+ /**
+ * This method is used to tell which errors you expect to get.
+ * Expected errors are always returned with error mode
+ * PEAR_ERROR_RETURN. Expected error codes are stored in a stack,
+ * and this method pushes a new element onto it. The list of
+ * expected errors are in effect until they are popped off the
+ * stack with the popExpect() method.
+ *
+ * Note that this method can not be called statically
+ *
+ * @param mixed $code a single error code or an array of error codes to expect
+ *
+ * @return int the new depth of the "expected errors" stack
+ * @access public
+ */
+ function expectError($code = '*')
+ {
+ if (is_array($code)) {
+ array_push($this->_expected_errors, $code);
+ } else {
+ array_push($this->_expected_errors, array($code));
+ }
+ return sizeof($this->_expected_errors);
+ }
+
+ // }}}
+ // {{{ popExpect()
+
+ /**
+ * This method pops one element off the expected error codes
+ * stack.
+ *
+ * @return array the list of error codes that were popped
+ */
+ function popExpect()
+ {
+ return array_pop($this->_expected_errors);
+ }
+
+ // }}}
+ // {{{ _checkDelExpect()
+
+ /**
+ * This method checks unsets an error code if available
+ *
+ * @param mixed error code
+ * @return bool true if the error code was unset, false otherwise
+ * @access private
+ * @since PHP 4.3.0
+ */
+ function _checkDelExpect($error_code)
+ {
+ $deleted = false;
+
+ foreach ($this->_expected_errors AS $key => $error_array) {
+ if (in_array($error_code, $error_array)) {
+ unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
+ $deleted = true;
+ }
+
+ // clean up empty arrays
+ if (0 == count($this->_expected_errors[$key])) {
+ unset($this->_expected_errors[$key]);
+ }
+ }
+ return $deleted;
+ }
+
+ // }}}
+ // {{{ delExpect()
+
+ /**
+ * This method deletes all occurences of the specified element from
+ * the expected error codes stack.
+ *
+ * @param mixed $error_code error code that should be deleted
+ * @return mixed list of error codes that were deleted or error
+ * @access public
+ * @since PHP 4.3.0
+ */
+ function delExpect($error_code)
+ {
+ $deleted = false;
+
+ if ((is_array($error_code) && (0 != count($error_code)))) {
+ // $error_code is a non-empty array here;
+ // we walk through it trying to unset all
+ // values
+ foreach($error_code as $key => $error) {
+ if ($this->_checkDelExpect($error)) {
+ $deleted = true;
+ } else {
+ $deleted = false;
+ }
+ }
+ return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
+ } elseif (!empty($error_code)) {
+ // $error_code comes alone, trying to unset it
+ if ($this->_checkDelExpect($error_code)) {
+ return true;
+ } else {
+ return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
+ }
+ } else {
+ // $error_code is empty
+ return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
+ }
+ }
+
+ // }}}
+ // {{{ raiseError()
+
+ /**
+ * This method is a wrapper that returns an instance of the
+ * configured error class with this object's default error
+ * handling applied. If the $mode and $options parameters are not
+ * specified, the object's defaults are used.
+ *
+ * @param mixed $message a text error message or a PEAR error object
+ *
+ * @param int $code a numeric error code (it is up to your class
+ * to define these if you want to use codes)
+ *
+ * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
+ * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
+ * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.
+ *
+ * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter
+ * specifies the PHP-internal error level (one of
+ * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
+ * If $mode is PEAR_ERROR_CALLBACK, this
+ * parameter specifies the callback function or
+ * method. In other error modes this parameter
+ * is ignored.
+ *
+ * @param string $userinfo If you need to pass along for example debug
+ * information, this parameter is meant for that.
+ *
+ * @param string $error_class The returned error object will be
+ * instantiated from this class, if specified.
+ *
+ * @param bool $skipmsg If true, raiseError will only pass error codes,
+ * the error message parameter will be dropped.
+ *
+ * @access public
+ * @return object a PEAR error object
+ * @see PEAR::setErrorHandling
+ * @since PHP 4.0.5
+ */
+ function &raiseError($message = null,
+ $code = null,
+ $mode = null,
+ $options = null,
+ $userinfo = null,
+ $error_class = null,
+ $skipmsg = false)
+ {
+ // The error is yet a PEAR error object
+ if (is_object($message)) {
+ $code = $message->getCode();
+ $userinfo = $message->getUserInfo();
+ $error_class = $message->getType();
+ $message->error_message_prefix = '';
+ $message = $message->getMessage();
+ }
+
+ if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) {
+ if ($exp[0] == "*" ||
+ (is_int(reset($exp)) && in_array($code, $exp)) ||
+ (is_string(reset($exp)) && in_array($message, $exp))) {
+ $mode = PEAR_ERROR_RETURN;
+ }
+ }
+ // No mode given, try global ones
+ if ($mode === null) {
+ // Class error handler
+ if (isset($this) && isset($this->_default_error_mode)) {
+ $mode = $this->_default_error_mode;
+ $options = $this->_default_error_options;
+ // Global error handler
+ } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {
+ $mode = $GLOBALS['_PEAR_default_error_mode'];
+ $options = $GLOBALS['_PEAR_default_error_options'];
+ }
+ }
+
+ if ($error_class !== null) {
+ $ec = $error_class;
+ } elseif (isset($this) && isset($this->_error_class)) {
+ $ec = $this->_error_class;
+ } else {
+ $ec = 'PEAR_Error';
+ }
+ if (intval(PHP_VERSION) < 5) {
+ // little non-eval hack to fix bug #12147
+ include 'PEAR/FixPHP5PEARWarnings.php';
+ return $a;
+ }
+ if ($skipmsg) {
+ $a = new $ec($code, $mode, $options, $userinfo);
+ } else {
+ $a = new $ec($message, $code, $mode, $options, $userinfo);
+ }
+ return $a;
+ }
+
+ // }}}
+ // {{{ throwError()
+
+ /**
+ * Simpler form of raiseError with fewer options. In most cases
+ * message, code and userinfo are enough.
+ *
+ * @param string $message
+ *
+ */
+ function &throwError($message = null,
+ $code = null,
+ $userinfo = null)
+ {
+ if (isset($this) && ($this instanceof PEAR)) {
+ $a = &$this->raiseError($message, $code, null, null, $userinfo);
+ return $a;
+ } else {
+ $a = &PEAR::raiseError($message, $code, null, null, $userinfo);
+ return $a;
+ }
+ }
+
+ // }}}
+ function staticPushErrorHandling($mode, $options = null)
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ $def_mode = &$GLOBALS['_PEAR_default_error_mode'];
+ $def_options = &$GLOBALS['_PEAR_default_error_options'];
+ $stack[] = array($def_mode, $def_options);
+ switch ($mode) {
+ case PEAR_ERROR_EXCEPTION:
+ case PEAR_ERROR_RETURN:
+ case PEAR_ERROR_PRINT:
+ case PEAR_ERROR_TRIGGER:
+ case PEAR_ERROR_DIE:
+ case null:
+ $def_mode = $mode;
+ $def_options = $options;
+ break;
+
+ case PEAR_ERROR_CALLBACK:
+ $def_mode = $mode;
+ // class/object method callback
+ if (is_callable($options)) {
+ $def_options = $options;
+ } else {
+ trigger_error("invalid error callback", E_USER_WARNING);
+ }
+ break;
+
+ default:
+ trigger_error("invalid error mode", E_USER_WARNING);
+ break;
+ }
+ $stack[] = array($mode, $options);
+ return true;
+ }
+
+ function staticPopErrorHandling()
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ $setmode = &$GLOBALS['_PEAR_default_error_mode'];
+ $setoptions = &$GLOBALS['_PEAR_default_error_options'];
+ array_pop($stack);
+ list($mode, $options) = $stack[sizeof($stack) - 1];
+ array_pop($stack);
+ switch ($mode) {
+ case PEAR_ERROR_EXCEPTION:
+ case PEAR_ERROR_RETURN:
+ case PEAR_ERROR_PRINT:
+ case PEAR_ERROR_TRIGGER:
+ case PEAR_ERROR_DIE:
+ case null:
+ $setmode = $mode;
+ $setoptions = $options;
+ break;
+
+ case PEAR_ERROR_CALLBACK:
+ $setmode = $mode;
+ // class/object method callback
+ if (is_callable($options)) {
+ $setoptions = $options;
+ } else {
+ trigger_error("invalid error callback", E_USER_WARNING);
+ }
+ break;
+
+ default:
+ trigger_error("invalid error mode", E_USER_WARNING);
+ break;
+ }
+ return true;
+ }
+
+ // {{{ pushErrorHandling()
+
+ /**
+ * Push a new error handler on top of the error handler options stack. With this
+ * you can easily override the actual error handler for some code and restore
+ * it later with popErrorHandling.
+ *
+ * @param mixed $mode (same as setErrorHandling)
+ * @param mixed $options (same as setErrorHandling)
+ *
+ * @return bool Always true
+ *
+ * @see PEAR::setErrorHandling
+ */
+ function pushErrorHandling($mode, $options = null)
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ if (isset($this) && ($this instanceof PEAR)) {
+ $def_mode = &$this->_default_error_mode;
+ $def_options = &$this->_default_error_options;
+ } else {
+ $def_mode = &$GLOBALS['_PEAR_default_error_mode'];
+ $def_options = &$GLOBALS['_PEAR_default_error_options'];
+ }
+ $stack[] = array($def_mode, $def_options);
+
+ if (isset($this) && ($this instanceof PEAR)) {
+ $this->setErrorHandling($mode, $options);
+ } else {
+ PEAR::setErrorHandling($mode, $options);
+ }
+ $stack[] = array($mode, $options);
+ return true;
+ }
+
+ // }}}
+ // {{{ popErrorHandling()
+
+ /**
+ * Pop the last error handler used
+ *
+ * @return bool Always true
+ *
+ * @see PEAR::pushErrorHandling
+ */
+ function popErrorHandling()
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ array_pop($stack);
+ list($mode, $options) = $stack[sizeof($stack) - 1];
+ array_pop($stack);
+ if (isset($this) && ($this instanceof PEAR)) {
+ $this->setErrorHandling($mode, $options);
+ } else {
+ PEAR::setErrorHandling($mode, $options);
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ loadExtension()
+
+ /**
+ * OS independant PHP extension load. Remember to take care
+ * on the correct extension name for case sensitive OSes.
+ *
+ * @param string $ext The extension name
+ * @return bool Success or not on the dl() call
+ */
+ function loadExtension($ext)
+ {
+ if (!extension_loaded($ext)) {
+ // if either returns true dl() will produce a FATAL error, stop that
+ if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) {
+ return false;
+ }
+ if (OS_WINDOWS) {
+ $suffix = '.dll';
+ } elseif (PHP_OS == 'HP-UX') {
+ $suffix = '.sl';
+ } elseif (PHP_OS == 'AIX') {
+ $suffix = '.a';
+ } elseif (PHP_OS == 'OSX') {
+ $suffix = '.bundle';
+ } else {
+ $suffix = '.so';
+ }
+ return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
+ }
+ return true;
+ }
+
+ // }}}
+}
+
+// {{{ _PEAR_call_destructors()
+
+function _PEAR_call_destructors()
+{
+ global $_PEAR_destructor_object_list;
+ if (is_array($_PEAR_destructor_object_list) &&
+ sizeof($_PEAR_destructor_object_list))
+ {
+ reset($_PEAR_destructor_object_list);
+ if (PEAR::getStaticProperty('PEAR', 'destructlifo')) {
+ $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
+ }
+ while (list($k, $objref) = each($_PEAR_destructor_object_list)) {
+ $classname = get_class($objref);
+ while ($classname) {
+ $destructor = "_$classname";
+ if (method_exists($objref, $destructor)) {
+ $objref->$destructor();
+ break;
+ } else {
+ $classname = get_parent_class($classname);
+ }
+ }
+ }
+ // Empty the object list to ensure that destructors are
+ // not called more than once.
+ $_PEAR_destructor_object_list = array();
+ }
+
+ // Now call the shutdown functions
+ if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) {
+ foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
+ call_user_func_array($value[0], $value[1]);
+ }
+ }
+}
+
+// }}}
+/**
+ * Standard PEAR error class for PHP 4
+ *
+ * This class is supserseded by {@link PEAR_Exception} in PHP 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Tomas V.V. Cox
+ * @author Gregory Beaver
+ * @copyright 1997-2006 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/manual/en/core.pear.pear-error.php
+ * @see PEAR::raiseError(), PEAR::throwError()
+ * @since Class available since PHP 4.0.2
+ */
+class PEAR_Error
+{
+ // {{{ properties
+
+ var $error_message_prefix = '';
+ var $mode = PEAR_ERROR_RETURN;
+ var $level = E_USER_NOTICE;
+ var $code = -1;
+ var $message = '';
+ var $userinfo = '';
+ var $backtrace = null;
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * PEAR_Error constructor
+ *
+ * @param string $message message
+ *
+ * @param int $code (optional) error code
+ *
+ * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN,
+ * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
+ * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
+ *
+ * @param mixed $options (optional) error level, _OR_ in the case of
+ * PEAR_ERROR_CALLBACK, the callback function or object/method
+ * tuple.
+ *
+ * @param string $userinfo (optional) additional user/debug info
+ *
+ * @access public
+ *
+ */
+ function __construct(){}
+
+ function PEAR_Error($message = 'unknown error', $code = null,
+ $mode = null, $options = null, $userinfo = null)
+ {
+ if ($mode === null) {
+ $mode = PEAR_ERROR_RETURN;
+ }
+ $this->message = $message;
+ $this->code = $code;
+ $this->mode = $mode;
+ $this->userinfo = $userinfo;
+ if (!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) {
+ $this->backtrace = debug_backtrace();
+ if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
+ unset($this->backtrace[0]['object']);
+ }
+ }
+ if ($mode & PEAR_ERROR_CALLBACK) {
+ $this->level = E_USER_NOTICE;
+ $this->callback = $options;
+ } else {
+ if ($options === null) {
+ $options = E_USER_NOTICE;
+ }
+ $this->level = $options;
+ $this->callback = null;
+ }
+ if ($this->mode & PEAR_ERROR_PRINT) {
+ if (is_null($options) || is_int($options)) {
+ $format = "%s";
+ } else {
+ $format = $options;
+ }
+ printf($format, $this->getMessage());
+ }
+ if ($this->mode & PEAR_ERROR_TRIGGER) {
+ trigger_error($this->getMessage(), $this->level);
+ }
+ if ($this->mode & PEAR_ERROR_DIE) {
+ $msg = $this->getMessage();
+ if (is_null($options) || is_int($options)) {
+ $format = "%s";
+ if (substr($msg, -1) != "\n") {
+ $msg .= "\n";
+ }
+ } else {
+ $format = $options;
+ }
+ die(sprintf($format, $msg));
+ }
+ if ($this->mode & PEAR_ERROR_CALLBACK) {
+ if (is_callable($this->callback)) {
+ call_user_func($this->callback, $this);
+ }
+ }
+ if ($this->mode & PEAR_ERROR_EXCEPTION) {
+ trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
+ eval('$e = new Exception($this->message, $this->code);throw($e);');
+ }
+ }
+
+ // }}}
+ // {{{ getMode()
+
+ /**
+ * Get the error mode from an error object.
+ *
+ * @return int error mode
+ * @access public
+ */
+ function getMode() {
+ return $this->mode;
+ }
+
+ // }}}
+ // {{{ getCallback()
+
+ /**
+ * Get the callback function/method from an error object.
+ *
+ * @return mixed callback function or object/method array
+ * @access public
+ */
+ function getCallback() {
+ return $this->callback;
+ }
+
+ // }}}
+ // {{{ getMessage()
+
+
+ /**
+ * Get the error message from an error object.
+ *
+ * @return string full error message
+ * @access public
+ */
+ function getMessage()
+ {
+ return ($this->error_message_prefix . $this->message);
+ }
+
+
+ // }}}
+ // {{{ getCode()
+
+ /**
+ * Get error code from an error object
+ *
+ * @return int error code
+ * @access public
+ */
+ function getCode()
+ {
+ return $this->code;
+ }
+
+ // }}}
+ // {{{ getType()
+
+ /**
+ * Get the name of this error/exception.
+ *
+ * @return string error/exception name (type)
+ * @access public
+ */
+ function getType()
+ {
+ return get_class($this);
+ }
+
+ // }}}
+ // {{{ getUserInfo()
+
+ /**
+ * Get additional user-supplied information.
+ *
+ * @return string user-supplied information
+ * @access public
+ */
+ function getUserInfo()
+ {
+ return $this->userinfo;
+ }
+
+ // }}}
+ // {{{ getDebugInfo()
+
+ /**
+ * Get additional debug information supplied by the application.
+ *
+ * @return string debug information
+ * @access public
+ */
+ function getDebugInfo()
+ {
+ return $this->getUserInfo();
+ }
+
+ // }}}
+ // {{{ getBacktrace()
+
+ /**
+ * Get the call backtrace from where the error was generated.
+ * Supported with PHP 4.3.0 or newer.
+ *
+ * @param int $frame (optional) what frame to fetch
+ * @return array Backtrace, or NULL if not available.
+ * @access public
+ */
+ function getBacktrace($frame = null)
+ {
+ if (defined('PEAR_IGNORE_BACKTRACE')) {
+ return null;
+ }
+ if ($frame === null) {
+ return $this->backtrace;
+ }
+ return $this->backtrace[$frame];
+ }
+
+ // }}}
+ // {{{ addUserInfo()
+
+ function addUserInfo($info)
+ {
+ if (empty($this->userinfo)) {
+ $this->userinfo = $info;
+ } else {
+ $this->userinfo .= " ** $info";
+ }
+ }
+
+ // }}}
+ // {{{ toString()
+ function __toString()
+ {
+ return $this->getMessage();
+ }
+ // }}}
+ // {{{ toString()
+
+ /**
+ * Make a string representation of this object.
+ *
+ * @return string a string with an object summary
+ * @access public
+ */
+ function toString() {
+ $modes = array();
+ $levels = array(E_USER_NOTICE => 'notice',
+ E_USER_WARNING => 'warning',
+ E_USER_ERROR => 'error');
+ if ($this->mode & PEAR_ERROR_CALLBACK) {
+ if (is_array($this->callback)) {
+ $callback = (is_object($this->callback[0]) ?
+ strtolower(get_class($this->callback[0])) :
+ $this->callback[0]) . '::' .
+ $this->callback[1];
+ } else {
+ $callback = $this->callback;
+ }
+ return sprintf('[%s: message="%s" code=%d mode=callback '.
+ 'callback=%s prefix="%s" info="%s"]',
+ strtolower(get_class($this)), $this->message, $this->code,
+ $callback, $this->error_message_prefix,
+ $this->userinfo);
+ }
+ if ($this->mode & PEAR_ERROR_PRINT) {
+ $modes[] = 'print';
+ }
+ if ($this->mode & PEAR_ERROR_TRIGGER) {
+ $modes[] = 'trigger';
+ }
+ if ($this->mode & PEAR_ERROR_DIE) {
+ $modes[] = 'die';
+ }
+ if ($this->mode & PEAR_ERROR_RETURN) {
+ $modes[] = 'return';
+ }
+ return sprintf('[%s: message="%s" code=%d mode=%s level=%s '.
+ 'prefix="%s" info="%s"]',
+ strtolower(get_class($this)), $this->message, $this->code,
+ implode("|", $modes), $levels[$this->level],
+ $this->error_message_prefix,
+ $this->userinfo);
+ }
+
+ // }}}
+}
+
+/*
+ * Local Variables:
+ * mode: php
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Autoloader.php b/vendor/library/Excel/phpxls/PEAR/Autoloader.php
new file mode 100644
index 0000000..07c4de1
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Autoloader.php
@@ -0,0 +1,223 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Autoloader.php,v 1.14 2008/01/03 20:26:34 cellog Exp $
+ * @link http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader
+ * @since File available since Release 0.1
+ * @deprecated File deprecated in Release 1.4.0a1
+ */
+
+// /* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+if (!extension_loaded("overload")) {
+ // die hard without ext/overload
+ die("Rebuild PHP with the `overload' extension to use PEAR_Autoloader");
+}
+
+/**
+ * Include for PEAR_Error and PEAR classes
+ */
+require_once "PEAR.php";
+
+/**
+ * This class is for objects where you want to separate the code for
+ * some methods into separate classes. This is useful if you have a
+ * class with not-frequently-used methods that contain lots of code
+ * that you would like to avoid always parsing.
+ *
+ * The PEAR_Autoloader class provides autoloading and aggregation.
+ * The autoloading lets you set up in which classes the separated
+ * methods are found. Aggregation is the technique used to import new
+ * methods, an instance of each class providing separated methods is
+ * stored and called every time the aggregated method is called.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader
+ * @since File available since Release 0.1
+ * @deprecated File deprecated in Release 1.4.0a1
+ */
+class PEAR_Autoloader extends PEAR
+{
+ // {{{ properties
+
+ /**
+ * Map of methods and classes where they are defined
+ *
+ * @var array
+ *
+ * @access private
+ */
+ var $_autoload_map = array();
+
+ /**
+ * Map of methods and aggregate objects
+ *
+ * @var array
+ *
+ * @access private
+ */
+ var $_method_map = array();
+
+ // }}}
+ // {{{ addAutoload()
+
+ /**
+ * Add one or more autoload entries.
+ *
+ * @param string $method which method to autoload
+ *
+ * @param string $classname (optional) which class to find the method in.
+ * If the $method parameter is an array, this
+ * parameter may be omitted (and will be ignored
+ * if not), and the $method parameter will be
+ * treated as an associative array with method
+ * names as keys and class names as values.
+ *
+ * @return void
+ *
+ * @access public
+ */
+ function addAutoload($method, $classname = null)
+ {
+ if (is_array($method)) {
+ array_walk($method, create_function('$a,&$b', '$b = strtolower($b);'));
+ $this->_autoload_map = array_merge($this->_autoload_map, $method);
+ } else {
+ $this->_autoload_map[strtolower($method)] = $classname;
+ }
+ }
+
+ // }}}
+ // {{{ removeAutoload()
+
+ /**
+ * Remove an autoload entry.
+ *
+ * @param string $method which method to remove the autoload entry for
+ *
+ * @return bool TRUE if an entry was removed, FALSE if not
+ *
+ * @access public
+ */
+ function removeAutoload($method)
+ {
+ $method = strtolower($method);
+ $ok = isset($this->_autoload_map[$method]);
+ unset($this->_autoload_map[$method]);
+ return $ok;
+ }
+
+ // }}}
+ // {{{ addAggregateObject()
+
+ /**
+ * Add an aggregate object to this object. If the specified class
+ * is not defined, loading it will be attempted following PEAR's
+ * file naming scheme. All the methods in the class will be
+ * aggregated, except private ones (name starting with an
+ * underscore) and constructors.
+ *
+ * @param string $classname what class to instantiate for the object.
+ *
+ * @return void
+ *
+ * @access public
+ */
+ function addAggregateObject($classname)
+ {
+ $classname = strtolower($classname);
+ if (!class_exists($classname)) {
+ $include_file = preg_replace('/[^a-z0-9]/i', '_', $classname);
+ include_once $include_file;
+ }
+ $obj =& new $classname;
+ $methods = get_class_methods($classname);
+ foreach ($methods as $method) {
+ // don't import priviate methods and constructors
+ if ($method{0} != '_' && $method != $classname) {
+ $this->_method_map[$method] = $obj;
+ }
+ }
+ }
+
+ // }}}
+ // {{{ removeAggregateObject()
+
+ /**
+ * Remove an aggregate object.
+ *
+ * @param string $classname the class of the object to remove
+ *
+ * @return bool TRUE if an object was removed, FALSE if not
+ *
+ * @access public
+ */
+ function removeAggregateObject($classname)
+ {
+ $ok = false;
+ $classname = strtolower($classname);
+ reset($this->_method_map);
+ while (list($method, $obj) = each($this->_method_map)) {
+ if (is_a($obj, $classname)) {
+ unset($this->_method_map[$method]);
+ $ok = true;
+ }
+ }
+ return $ok;
+ }
+
+ // }}}
+ // {{{ __call()
+
+ /**
+ * Overloaded object call handler, called each time an
+ * undefined/aggregated method is invoked. This method repeats
+ * the call in the right aggregate object and passes on the return
+ * value.
+ *
+ * @param string $method which method that was called
+ *
+ * @param string $args An array of the parameters passed in the
+ * original call
+ *
+ * @return mixed The return value from the aggregated method, or a PEAR
+ * error if the called method was unknown.
+ */
+ function __call($method, $args, &$retval)
+ {
+ $method = strtolower($method);
+ if (empty($this->_method_map[$method]) && isset($this->_autoload_map[$method])) {
+ $this->addAggregateObject($this->_autoload_map[$method]);
+ }
+ if (isset($this->_method_map[$method])) {
+ $retval = call_user_func_array(array($this->_method_map[$method], $method), $args);
+ return true;
+ }
+ return false;
+ }
+
+ // }}}
+}
+
+overload("PEAR_Autoloader");
+
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Builder.php b/vendor/library/Excel/phpxls/PEAR/Builder.php
new file mode 100644
index 0000000..f7986c0
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Builder.php
@@ -0,0 +1,486 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Builder.php,v 1.34 2008/05/12 23:43:21 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ *
+ * TODO: log output parameters in PECL command line
+ * TODO: msdev path in configuration
+ */
+
+/**
+ * Needed for extending PEAR_Builder
+ */
+require_once 'PEAR/Common.php';
+require_once 'PEAR/PackageFile.php';
+/**
+ * Class to handle building (compiling) extensions.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since PHP 4.0.2
+ * @see http://pear.php.net/manual/en/core.ppm.pear-builder.php
+ */
+class PEAR_Builder extends PEAR_Common
+{
+ // {{{ properties
+
+ var $php_api_version = 0;
+ var $zend_module_api_no = 0;
+ var $zend_extension_api_no = 0;
+
+ var $extensions_built = array();
+
+ /**
+ * @var string Used for reporting when it is not possible to pass function
+ * via extra parameter, e.g. log, msdevCallback
+ */
+ var $current_callback = null;
+
+ // used for msdev builds
+ var $_lastline = null;
+ var $_firstline = null;
+ // }}}
+ // {{{ constructor
+
+ /**
+ * PEAR_Builder constructor.
+ *
+ * @param object $ui user interface object (instance of PEAR_Frontend_*)
+ *
+ * @access public
+ */
+ function PEAR_Builder(&$ui)
+ {
+ parent::PEAR_Common();
+ $this->setFrontendObject($ui);
+ }
+
+ // }}}
+
+ // {{{ _build_win32()
+
+ /**
+ * Build an extension from source on windows.
+ * requires msdev
+ */
+ function _build_win32($descfile, $callback = null)
+ {
+ if (is_object($descfile)) {
+ $pkg = $descfile;
+ $descfile = $pkg->getPackageFile();
+ } else {
+ $pf = &new PEAR_PackageFile($this->config, $this->debug);
+ $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($pkg)) {
+ return $pkg;
+ }
+ }
+ $dir = dirname($descfile);
+ $old_cwd = getcwd();
+
+ if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) {
+ return $this->raiseError("could not chdir to $dir");
+ }
+ // packages that were in a .tar have the packagefile in this directory
+ $vdir = $pkg->getPackage() . '-' . $pkg->getVersion();
+ if (file_exists($dir) && is_dir($vdir)) {
+ if (chdir($vdir)) {
+ $dir = getcwd();
+ } else {
+ return $this->raiseError("could not chdir to " . realpath($vdir));
+ }
+ }
+
+ $this->log(2, "building in $dir");
+
+ $dsp = $pkg->getPackage().'.dsp';
+ if (!file_exists("$dir/$dsp")) {
+ return $this->raiseError("The DSP $dsp does not exist.");
+ }
+ // XXX TODO: make release build type configurable
+ $command = 'msdev '.$dsp.' /MAKE "'.$pkg->getPackage(). ' - Release"';
+
+ $err = $this->_runCommand($command, array(&$this, 'msdevCallback'));
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+
+ // figure out the build platform and type
+ $platform = 'Win32';
+ $buildtype = 'Release';
+ if (preg_match('/.*?'.$pkg->getPackage().'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) {
+ $platform = $matches[1];
+ $buildtype = $matches[2];
+ }
+
+ if (preg_match('/(.*)?\s-\s(\d+).*?(\d+)/',$this->_lastline,$matches)) {
+ if ($matches[2]) {
+ // there were errors in the build
+ return $this->raiseError("There were errors during compilation.");
+ }
+ $out = $matches[1];
+ } else {
+ return $this->raiseError("Did not understand the completion status returned from msdev.exe.");
+ }
+
+ // msdev doesn't tell us the output directory :/
+ // open the dsp, find /out and use that directory
+ $dsptext = join(file($dsp),'');
+
+ // this regex depends on the build platform and type having been
+ // correctly identified above.
+ $regex ='/.*?!IF\s+"\$\(CFG\)"\s+==\s+("'.
+ $pkg->getPackage().'\s-\s'.
+ $platform.'\s'.
+ $buildtype.'").*?'.
+ '\/out:"(.*?)"/is';
+
+ if ($dsptext && preg_match($regex,$dsptext,$matches)) {
+ // what we get back is a relative path to the output file itself.
+ $outfile = realpath($matches[2]);
+ } else {
+ return $this->raiseError("Could not retrieve output information from $dsp.");
+ }
+ // realpath returns false if the file doesn't exist
+ if ($outfile && copy($outfile, "$dir/$out")) {
+ $outfile = "$dir/$out";
+ }
+
+ $built_files[] = array(
+ 'file' => "$outfile",
+ 'php_api' => $this->php_api_version,
+ 'zend_mod_api' => $this->zend_module_api_no,
+ 'zend_ext_api' => $this->zend_extension_api_no,
+ );
+
+ return $built_files;
+ }
+ // }}}
+
+ // {{{ msdevCallback()
+ function msdevCallback($what, $data)
+ {
+ if (!$this->_firstline)
+ $this->_firstline = $data;
+ $this->_lastline = $data;
+ call_user_func($this->current_callback, $what, $data);
+ }
+ // }}}
+
+ // {{{ _harventInstDir
+ /**
+ * @param string
+ * @param string
+ * @param array
+ * @access private
+ */
+ function _harvestInstDir($dest_prefix, $dirname, &$built_files)
+ {
+ $d = opendir($dirname);
+ if (!$d)
+ return false;
+
+ $ret = true;
+ while (($ent = readdir($d)) !== false) {
+ if ($ent{0} == '.')
+ continue;
+
+ $full = $dirname . DIRECTORY_SEPARATOR . $ent;
+ if (is_dir($full)) {
+ if (!$this->_harvestInstDir(
+ $dest_prefix . DIRECTORY_SEPARATOR . $ent,
+ $full, $built_files)) {
+ $ret = false;
+ break;
+ }
+ } else {
+ $dest = $dest_prefix . DIRECTORY_SEPARATOR . $ent;
+ $built_files[] = array(
+ 'file' => $full,
+ 'dest' => $dest,
+ 'php_api' => $this->php_api_version,
+ 'zend_mod_api' => $this->zend_module_api_no,
+ 'zend_ext_api' => $this->zend_extension_api_no,
+ );
+ }
+ }
+ closedir($d);
+ return $ret;
+ }
+
+ // }}}
+
+ // {{{ build()
+
+ /**
+ * Build an extension from source. Runs "phpize" in the source
+ * directory, but compiles in a temporary directory
+ * (/var/tmp/pear-build-USER/PACKAGE-VERSION).
+ *
+ * @param string|PEAR_PackageFile_v* $descfile path to XML package description file, or
+ * a PEAR_PackageFile object
+ *
+ * @param mixed $callback callback function used to report output,
+ * see PEAR_Builder::_runCommand for details
+ *
+ * @return array an array of associative arrays with built files,
+ * format:
+ * array( array( 'file' => '/path/to/ext.so',
+ * 'php_api' => YYYYMMDD,
+ * 'zend_mod_api' => YYYYMMDD,
+ * 'zend_ext_api' => YYYYMMDD ),
+ * ... )
+ *
+ * @access public
+ *
+ * @see PEAR_Builder::_runCommand
+ */
+ function build($descfile, $callback = null)
+ {
+ $this->current_callback = $callback;
+ if (PEAR_OS == "Windows") {
+ return $this->_build_win32($descfile,$callback);
+ }
+ if (PEAR_OS != 'Unix') {
+ return $this->raiseError("building extensions not supported on this platform");
+ }
+ if (is_object($descfile)) {
+ $pkg = $descfile;
+ $descfile = $pkg->getPackageFile();
+ if (is_a($pkg, 'PEAR_PackageFile_v1')) {
+ $dir = dirname($descfile);
+ } else {
+ $dir = $pkg->_config->get('temp_dir') . '/' . $pkg->getName();
+ // automatically delete at session end
+ $this->addTempFile($dir);
+ }
+ } else {
+ $pf = &new PEAR_PackageFile($this->config);
+ $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($pkg)) {
+ return $pkg;
+ }
+ $dir = dirname($descfile);
+ }
+ $old_cwd = getcwd();
+ if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) {
+ return $this->raiseError("could not chdir to $dir");
+ }
+ $vdir = $pkg->getPackage() . '-' . $pkg->getVersion();
+ if (is_dir($vdir)) {
+ chdir($vdir);
+ }
+ $dir = getcwd();
+ $this->log(2, "building in $dir");
+ putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH'));
+ $err = $this->_runCommand("phpize", array(&$this, 'phpizeCallback'));
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+ if (!$err) {
+ return $this->raiseError("`phpize' failed");
+ }
+
+ // {{{ start of interactive part
+ $configure_command = "$dir/configure";
+ $configure_options = $pkg->getConfigureOptions();
+ if ($configure_options) {
+ foreach ($configure_options as $o) {
+ $default = array_key_exists('default', $o) ? $o['default'] : null;
+ list($r) = $this->ui->userDialog('build',
+ array($o['prompt']),
+ array('text'),
+ array($default));
+ if (substr($o['name'], 0, 5) == 'with-' &&
+ ($r == 'yes' || $r == 'autodetect')) {
+ $configure_command .= " --$o[name]";
+ } else {
+ $configure_command .= " --$o[name]=".trim($r);
+ }
+ }
+ }
+ // }}} end of interactive part
+
+ // FIXME make configurable
+ if(!$user=getenv('USER')){
+ $user='defaultuser';
+ }
+ $build_basedir = "/var/tmp/pear-build-$user";
+ $build_dir = "$build_basedir/$vdir";
+ $inst_dir = "$build_basedir/install-$vdir";
+ $this->log(1, "building in $build_dir");
+ if (is_dir($build_dir)) {
+ System::rm(array('-rf', $build_dir));
+ }
+ if (!System::mkDir(array('-p', $build_dir))) {
+ return $this->raiseError("could not create build dir: $build_dir");
+ }
+ $this->addTempFile($build_dir);
+ if (!System::mkDir(array('-p', $inst_dir))) {
+ return $this->raiseError("could not create temporary install dir: $inst_dir");
+ }
+ $this->addTempFile($inst_dir);
+
+ if (getenv('MAKE')) {
+ $make_command = getenv('MAKE');
+ } else {
+ $make_command = 'make';
+ }
+ $to_run = array(
+ $configure_command,
+ $make_command,
+ "$make_command INSTALL_ROOT=\"$inst_dir\" install",
+ "find \"$inst_dir\" | xargs ls -dils"
+ );
+ if (!file_exists($build_dir) || !is_dir($build_dir) || !chdir($build_dir)) {
+ return $this->raiseError("could not chdir to $build_dir");
+ }
+ putenv('PHP_PEAR_VERSION=1.7.2');
+ foreach ($to_run as $cmd) {
+ $err = $this->_runCommand($cmd, $callback);
+ if (PEAR::isError($err)) {
+ chdir($old_cwd);
+ return $err;
+ }
+ if (!$err) {
+ chdir($old_cwd);
+ return $this->raiseError("`$cmd' failed");
+ }
+ }
+ if (!($dp = opendir("modules"))) {
+ chdir($old_cwd);
+ return $this->raiseError("no `modules' directory found");
+ }
+ $built_files = array();
+ $prefix = exec("php-config --prefix");
+ $this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files);
+ chdir($old_cwd);
+ return $built_files;
+ }
+
+ // }}}
+ // {{{ phpizeCallback()
+
+ /**
+ * Message callback function used when running the "phpize"
+ * program. Extracts the API numbers used. Ignores other message
+ * types than "cmdoutput".
+ *
+ * @param string $what the type of message
+ * @param mixed $data the message
+ *
+ * @return void
+ *
+ * @access public
+ */
+ function phpizeCallback($what, $data)
+ {
+ if ($what != 'cmdoutput') {
+ return;
+ }
+ $this->log(1, rtrim($data));
+ if (preg_match('/You should update your .aclocal.m4/', $data)) {
+ return;
+ }
+ $matches = array();
+ if (preg_match('/^\s+(\S[^:]+):\s+(\d{8})/', $data, $matches)) {
+ $member = preg_replace('/[^a-z]/', '_', strtolower($matches[1]));
+ $apino = (int)$matches[2];
+ if (isset($this->$member)) {
+ $this->$member = $apino;
+ //$msg = sprintf("%-22s : %d", $matches[1], $apino);
+ //$this->log(1, $msg);
+ }
+ }
+ }
+
+ // }}}
+ // {{{ _runCommand()
+
+ /**
+ * Run an external command, using a message callback to report
+ * output. The command will be run through popen and output is
+ * reported for every line with a "cmdoutput" message with the
+ * line string, including newlines, as payload.
+ *
+ * @param string $command the command to run
+ *
+ * @param mixed $callback (optional) function to use as message
+ * callback
+ *
+ * @return bool whether the command was successful (exit code 0
+ * means success, any other means failure)
+ *
+ * @access private
+ */
+ function _runCommand($command, $callback = null)
+ {
+ $this->log(1, "running: $command");
+ $pp = popen("$command 2>&1", "r");
+ if (!$pp) {
+ return $this->raiseError("failed to run `$command'");
+ }
+ if ($callback && $callback[0]->debug == 1) {
+ $olddbg = $callback[0]->debug;
+ $callback[0]->debug = 2;
+ }
+
+ while ($line = fgets($pp, 1024)) {
+ if ($callback) {
+ call_user_func($callback, 'cmdoutput', $line);
+ } else {
+ $this->log(2, rtrim($line));
+ }
+ }
+ if ($callback && isset($olddbg)) {
+ $callback[0]->debug = $olddbg;
+ }
+ if (is_resource($pp)) {
+ $exitcode = pclose($pp);
+ } else {
+ $exitcode = -1;
+ }
+ return ($exitcode == 0);
+ }
+
+ // }}}
+ // {{{ log()
+
+ function log($level, $msg)
+ {
+ if ($this->current_callback) {
+ if ($this->debug >= $level) {
+ call_user_func($this->current_callback, 'output', $msg);
+ }
+ return;
+ }
+ return PEAR_Common::log($level, $msg);
+ }
+
+ // }}}
+}
+
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/ChannelFile.php b/vendor/library/Excel/phpxls/PEAR/ChannelFile.php
new file mode 100644
index 0000000..407e3da
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/ChannelFile.php
@@ -0,0 +1,1615 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: ChannelFile.php,v 1.80 2008/01/03 20:26:34 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * Needed for error handling
+ */
+require_once 'PEAR/ErrorStack.php';
+require_once 'PEAR/XMLParser.php';
+require_once 'PEAR/Common.php';
+
+/**
+ * Error code if the channel.xml tag does not contain a valid version
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1);
+/**
+ * Error code if the channel.xml tag version is not supported (version 1.0 is the only supported version,
+ * currently
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2);
+
+/**
+ * Error code if parsing is attempted with no xml extension
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3);
+
+/**
+ * Error code if creating the xml parser resource fails
+ */
+define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4);
+
+/**
+ * Error code used for all sax xml parsing errors
+ */
+define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5);
+
+/**#@+
+ * Validation errors
+ */
+/**
+ * Error code when channel name is missing
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6);
+/**
+ * Error code when channel name is invalid
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7);
+/**
+ * Error code when channel summary is missing
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8);
+/**
+ * Error code when channel summary is multi-line
+ */
+define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9);
+/**
+ * Error code when channel server is missing for xmlrpc or soap protocol
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10);
+/**
+ * Error code when channel server is invalid for xmlrpc or soap protocol
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11);
+/**
+ * Error code when a mirror name is invalid
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21);
+/**
+ * Error code when a mirror type is invalid
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22);
+/**
+ * Error code when an attempt is made to generate xml, but the parsed content is invalid
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID', 23);
+/**
+ * Error code when an empty package name validate regex is passed in
+ */
+define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24);
+/**
+ * Error code when a tag has no version
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25);
+/**
+ * Error code when a tag has no name
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26);
+/**
+ * Error code when a tag has no name
+ */
+define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27);
+/**
+ * Error code when a tag has no version attribute
+ */
+define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28);
+/**
+ * Error code when a mirror does not exist but is called for in one of the set*
+ * methods.
+ */
+define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32);
+/**
+ * Error code when a server port is not numeric
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33);
+/**
+ * Error code when contains no version attribute
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34);
+/**
+ * Error code when contains no type attribute in a protocol definition
+ */
+define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35);
+/**
+ * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel
+ */
+define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36);
+/**
+ * Error code when ssl attribute is present and is not "yes"
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37);
+/**#@-*/
+
+/**
+ * Mirror types allowed. Currently only internet servers are recognized.
+ */
+$GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] = array('server');
+
+
+/**
+ * The Channel handling class
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_ChannelFile {
+ /**
+ * @access private
+ * @var PEAR_ErrorStack
+ * @access private
+ */
+ var $_stack;
+
+ /**
+ * Supported channel.xml versions, for parsing
+ * @var array
+ * @access private
+ */
+ var $_supportedVersions = array('1.0');
+
+ /**
+ * Parsed channel information
+ * @var array
+ * @access private
+ */
+ var $_channelInfo;
+
+ /**
+ * index into the subchannels array, used for parsing xml
+ * @var int
+ * @access private
+ */
+ var $_subchannelIndex;
+
+ /**
+ * index into the mirrors array, used for parsing xml
+ * @var int
+ * @access private
+ */
+ var $_mirrorIndex;
+
+ /**
+ * Flag used to determine the validity of parsed content
+ * @var boolean
+ * @access private
+ */
+ var $_isValid = false;
+
+ function PEAR_ChannelFile()
+ {
+ $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile');
+ $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
+ $this->_isValid = false;
+ }
+
+ /**
+ * @return array
+ * @access protected
+ */
+ function _getErrorMessage()
+ {
+ return
+ array(
+ PEAR_CHANNELFILE_ERROR_INVALID_VERSION =>
+ 'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%',
+ PEAR_CHANNELFILE_ERROR_NO_VERSION =>
+ 'No version number found in tag',
+ PEAR_CHANNELFILE_ERROR_NO_XML_EXT =>
+ '%error%',
+ PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER =>
+ 'Unable to create XML parser',
+ PEAR_CHANNELFILE_ERROR_PARSER_ERROR =>
+ '%error%',
+ PEAR_CHANNELFILE_ERROR_NO_NAME =>
+ 'Missing channel name',
+ PEAR_CHANNELFILE_ERROR_INVALID_NAME =>
+ 'Invalid channel %tag% "%name%"',
+ PEAR_CHANNELFILE_ERROR_NO_SUMMARY =>
+ 'Missing channel summary',
+ PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY =>
+ 'Channel summary should be on one line, but is multi-line',
+ PEAR_CHANNELFILE_ERROR_NO_HOST =>
+ 'Missing channel server for %type% server',
+ PEAR_CHANNELFILE_ERROR_INVALID_HOST =>
+ 'Server name "%server%" is invalid for %type% server',
+ PEAR_CHANNELFILE_ERROR_INVALID_MIRROR =>
+ 'Invalid mirror name "%name%", mirror type %type%',
+ PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE =>
+ 'Invalid mirror type "%type%"',
+ PEAR_CHANNELFILE_ERROR_INVALID =>
+ 'Cannot generate xml, contents are invalid',
+ PEAR_CHANNELFILE_ERROR_EMPTY_REGEX =>
+ 'packagenameregex cannot be empty',
+ PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION =>
+ '%parent% %protocol% function has no version',
+ PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME =>
+ '%parent% %protocol% function has no name',
+ PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE =>
+ '%parent% rest baseurl has no type',
+ PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME =>
+ 'Validation package has no name in tag',
+ PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION =>
+ 'Validation package "%package%" has no version',
+ PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND =>
+ 'Mirror "%mirror%" does not exist',
+ PEAR_CHANNELFILE_ERROR_INVALID_PORT =>
+ 'Port "%port%" must be numeric',
+ PEAR_CHANNELFILE_ERROR_NO_STATICVERSION =>
+ ' tag must contain version attribute',
+ PEAR_CHANNELFILE_URI_CANT_MIRROR =>
+ 'The __uri pseudo-channel cannot have mirrors',
+ PEAR_CHANNELFILE_ERROR_INVALID_SSL =>
+ '%server% has invalid ssl attribute "%ssl%" can only be yes or not present',
+ );
+ }
+
+ /**
+ * @param string contents of package.xml file
+ * @return bool success of parsing
+ */
+ function fromXmlString($data)
+ {
+ if (preg_match('/_supportedVersions)) {
+ $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error',
+ array('version' => $channelversion[1]));
+ return false;
+ }
+ $parser = new PEAR_XMLParser;
+ $result = $parser->parse($data);
+ if ($result !== true) {
+ if ($result->getCode() == 1) {
+ $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error',
+ array('error' => $result->getMessage()));
+ } else {
+ $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error');
+ }
+ return false;
+ }
+ $this->_channelInfo = $parser->getData();
+ return true;
+ } else {
+ $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data));
+ return false;
+ }
+ }
+
+ /**
+ * @return array
+ */
+ function toArray()
+ {
+ if (!$this->_isValid && !$this->validate()) {
+ return false;
+ }
+ return $this->_channelInfo;
+ }
+
+ /**
+ * @param array
+ * @static
+ * @return PEAR_ChannelFile|false false if invalid
+ */
+ static function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack')
+ {
+ $a = new PEAR_ChannelFile($compatibility, $stackClass);
+ $a->_fromArray($data);
+ if (!$a->validate()) {
+ $a = false;
+ return $a;
+ }
+ return $a;
+ }
+
+ /**
+ * Unlike {@link fromArray()} this does not do any validation
+ * @param array
+ * @static
+ * @return PEAR_ChannelFile
+ */
+ static function &fromArrayWithErrors($data, $compatibility = false,
+ $stackClass = 'PEAR_ErrorStack')
+ {
+ $a = new PEAR_ChannelFile($compatibility, $stackClass);
+ $a->_fromArray($data);
+ return $a;
+ }
+
+ /**
+ * @param array
+ * @access private
+ */
+ function _fromArray($data)
+ {
+ $this->_channelInfo = $data;
+ }
+
+ /**
+ * Wrapper to {@link PEAR_ErrorStack::getErrors()}
+ * @param boolean determines whether to purge the error stack after retrieving
+ * @return array
+ */
+ function getErrors($purge = false)
+ {
+ return $this->_stack->getErrors($purge);
+ }
+
+ /**
+ * Unindent given string (?)
+ *
+ * @param string $str The string that has to be unindented.
+ * @return string
+ * @access private
+ */
+ function _unIndent($str)
+ {
+ // remove leading newlines
+ $str = preg_replace('/^[\r\n]+/', '', $str);
+ // find whitespace at the beginning of the first line
+ $indent_len = strspn($str, " \t");
+ $indent = substr($str, 0, $indent_len);
+ $data = '';
+ // remove the same amount of whitespace from following lines
+ foreach (explode("\n", $str) as $line) {
+ if (substr($line, 0, $indent_len) == $indent) {
+ $data .= substr($line, $indent_len) . "\n";
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Parse a channel.xml file. Expects the name of
+ * a channel xml file as input.
+ *
+ * @param string $descfile name of channel xml file
+ * @return bool success of parsing
+ */
+ function fromXmlFile($descfile)
+ {
+ if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) ||
+ (!$fp = fopen($descfile, 'r'))) {
+ require_once 'PEAR.php';
+ return PEAR::raiseError("Unable to open $descfile");
+ }
+
+ // read the whole thing so we only get one cdata callback
+ // for each block of cdata
+ fclose($fp);
+ $data = file_get_contents($descfile);
+ return $this->fromXmlString($data);
+ }
+
+ /**
+ * Parse channel information from different sources
+ *
+ * This method is able to extract information about a channel
+ * from an .xml file or a string
+ *
+ * @access public
+ * @param string Filename of the source or the source itself
+ * @return bool
+ */
+ function fromAny($info)
+ {
+ if (is_string($info) && file_exists($info) && strlen($info) < 255) {
+ $tmp = substr($info, -4);
+ if ($tmp == '.xml') {
+ $info = $this->fromXmlFile($info);
+ } else {
+ $fp = fopen($info, "r");
+ $test = fread($fp, 5);
+ fclose($fp);
+ if ($test == "fromXmlFile($info);
+ }
+ }
+ if (PEAR::isError($info)) {
+ require_once 'PEAR.php';
+ return PEAR::raiseError($info);
+ }
+ }
+ if (is_string($info)) {
+ $info = $this->fromXmlString($info);
+ }
+ return $info;
+ }
+
+ /**
+ * Return an XML document based on previous parsing and modifications
+ *
+ * @return string XML data
+ *
+ * @access public
+ */
+ function toXml()
+ {
+ if (!$this->_isValid && !$this->validate()) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID);
+ return false;
+ }
+ if (!isset($this->_channelInfo['attribs']['version'])) {
+ $this->_channelInfo['attribs']['version'] = '1.0';
+ }
+ $channelInfo = $this->_channelInfo;
+ $ret = "\n";
+ $ret .= "
+ $channelInfo[name]
+ " . htmlspecialchars($channelInfo['summary'])."
+";
+ if (isset($channelInfo['suggestedalias'])) {
+ $ret .= ' ' . $channelInfo['suggestedalias'] . "\n";
+ }
+ if (isset($channelInfo['validatepackage'])) {
+ $ret .= ' ' .
+ htmlspecialchars($channelInfo['validatepackage']['_content']) .
+ "\n";
+ }
+ $ret .= " \n";
+ $ret .= ' _makeXmlrpcXml($channelInfo['servers']['primary']['xmlrpc'], ' ');
+ }
+ if (isset($channelInfo['servers']['primary']['rest'])) {
+ $ret .= $this->_makeRestXml($channelInfo['servers']['primary']['rest'], ' ');
+ }
+ if (isset($channelInfo['servers']['primary']['soap'])) {
+ $ret .= $this->_makeSoapXml($channelInfo['servers']['primary']['soap'], ' ');
+ }
+ $ret .= " \n";
+ if (isset($channelInfo['servers']['mirror'])) {
+ $ret .= $this->_makeMirrorsXml($channelInfo);
+ }
+ $ret .= " \n";
+ $ret .= "";
+ return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret));
+ }
+
+ /**
+ * Generate the tag
+ * @access private
+ */
+ function _makeXmlrpcXml($info, $indent)
+ {
+ $ret = $indent . "_makeFunctionsXml($info['function'], "$indent ");
+ $ret .= $indent . "\n";
+ return $ret;
+ }
+
+ /**
+ * Generate the tag
+ * @access private
+ */
+ function _makeSoapXml($info, $indent)
+ {
+ $ret = $indent . "_makeFunctionsXml($info['function'], "$indent ");
+ $ret .= $indent . "\n";
+ return $ret;
+ }
+
+ /**
+ * Generate the tag
+ * @access private
+ */
+ function _makeRestXml($info, $indent)
+ {
+ $ret = $indent . "\n";
+ if (!isset($info['baseurl'][0])) {
+ $info['baseurl'] = array($info['baseurl']);
+ }
+ foreach ($info['baseurl'] as $url) {
+ $ret .= "$indent \n";
+ }
+ $ret .= $indent . "\n";
+ return $ret;
+ }
+
+ /**
+ * Generate the tag
+ * @access private
+ */
+ function _makeMirrorsXml($channelInfo)
+ {
+ $ret = "";
+ if (!isset($channelInfo['servers']['mirror'][0])) {
+ $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']);
+ }
+ foreach ($channelInfo['servers']['mirror'] as $mirror) {
+ $ret .= ' _makeXmlrpcXml($mirror['xmlrpc'], ' ');
+ }
+ if (isset($mirror['rest'])) {
+ $ret .= $this->_makeRestXml($mirror['rest'], ' ');
+ }
+ if (isset($mirror['soap'])) {
+ $ret .= $this->_makeSoapXml($mirror['soap'], ' ');
+ }
+ $ret .= " \n";
+ } else {
+ $ret .= "/>\n";
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * Generate the tag
+ * @access private
+ */
+ function _makeFunctionsXml($functions, $indent, $rest = false)
+ {
+ $ret = '';
+ if (!isset($functions[0])) {
+ $functions = array($functions);
+ }
+ foreach ($functions as $function) {
+ $ret .= "$indent\n";
+ }
+ return $ret;
+ }
+
+ /**
+ * Validation error. Also marks the object contents as invalid
+ * @param error code
+ * @param array error information
+ * @access private
+ */
+ function _validateError($code, $params = array())
+ {
+ $this->_stack->push($code, 'error', $params);
+ $this->_isValid = false;
+ }
+
+ /**
+ * Validation warning. Does not mark the object contents invalid.
+ * @param error code
+ * @param array error information
+ * @access private
+ */
+ function _validateWarning($code, $params = array())
+ {
+ $this->_stack->push($code, 'warning', $params);
+ }
+
+ /**
+ * Validate parsed file.
+ *
+ * @access public
+ * @return boolean
+ */
+ function validate()
+ {
+ $this->_isValid = true;
+ $info = $this->_channelInfo;
+ if (empty($info['name'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME);
+ } elseif (!$this->validChannelServer($info['name'])) {
+ if ($info['name'] != '__uri') {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name',
+ 'name' => $info['name']));
+ }
+ }
+ if (empty($info['summary'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
+ } elseif (strpos(trim($info['summary']), "\n") !== false) {
+ $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
+ array('summary' => $info['summary']));
+ }
+ if (isset($info['suggestedalias'])) {
+ if (!$this->validChannelServer($info['suggestedalias'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
+ array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias']));
+ }
+ }
+ if (isset($info['localalias'])) {
+ if (!$this->validChannelServer($info['localalias'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
+ array('tag' => 'localalias', 'name' =>$info['localalias']));
+ }
+ }
+ if (isset($info['validatepackage'])) {
+ if (!isset($info['validatepackage']['_content'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME);
+ }
+ if (!isset($info['validatepackage']['attribs']['version'])) {
+ $content = isset($info['validatepackage']['_content']) ?
+ $info['validatepackage']['_content'] :
+ null;
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION,
+ array('package' => $content));
+ }
+ }
+ if (isset($info['servers']['primary']['attribs']['port']) &&
+ !is_numeric($info['servers']['primary']['attribs']['port'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT,
+ array('port' => $info['servers']['primary']['attribs']['port']));
+ }
+ if (isset($info['servers']['primary']['attribs']['ssl']) &&
+ $info['servers']['primary']['attribs']['ssl'] != 'yes') {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
+ array('ssl' => $info['servers']['primary']['attribs']['ssl'],
+ 'server' => $info['name']));
+ }
+
+ if (isset($info['servers']['primary']['xmlrpc']) &&
+ isset($info['servers']['primary']['xmlrpc']['function'])) {
+ $this->_validateFunctions('xmlrpc', $info['servers']['primary']['xmlrpc']['function']);
+ }
+ if (isset($info['servers']['primary']['soap']) &&
+ isset($info['servers']['primary']['soap']['function'])) {
+ $this->_validateFunctions('soap', $info['servers']['primary']['soap']['function']);
+ }
+ if (isset($info['servers']['primary']['rest']) &&
+ isset($info['servers']['primary']['rest']['baseurl'])) {
+ $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']);
+ }
+ if (isset($info['servers']['mirror'])) {
+ if ($this->_channelInfo['name'] == '__uri') {
+ $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR);
+ }
+ if (!isset($info['servers']['mirror'][0])) {
+ $info['servers']['mirror'] = array($info['servers']['mirror']);
+ }
+ foreach ($info['servers']['mirror'] as $mirror) {
+ if (!isset($mirror['attribs']['host'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST,
+ array('type' => 'mirror'));
+ } elseif (!$this->validChannelServer($mirror['attribs']['host'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST,
+ array('server' => $mirror['attribs']['host'], 'type' => 'mirror'));
+ }
+ if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
+ array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host']));
+ }
+ if (isset($mirror['xmlrpc'])) {
+ $this->_validateFunctions('xmlrpc',
+ $mirror['xmlrpc']['function'], $mirror['attribs']['host']);
+ }
+ if (isset($mirror['soap'])) {
+ $this->_validateFunctions('soap', $mirror['soap']['function'],
+ $mirror['attribs']['host']);
+ }
+ if (isset($mirror['rest'])) {
+ $this->_validateFunctions('rest', $mirror['rest']['baseurl'],
+ $mirror['attribs']['host']);
+ }
+ }
+ }
+ return $this->_isValid;
+ }
+
+ /**
+ * @param string xmlrpc or soap - protocol name this function applies to
+ * @param array the functions
+ * @param string the name of the parent element (mirror name, for instance)
+ */
+ function _validateFunctions($protocol, $functions, $parent = '')
+ {
+ if (!isset($functions[0])) {
+ $functions = array($functions);
+ }
+ foreach ($functions as $function) {
+ if (!isset($function['_content']) || empty($function['_content'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME,
+ array('parent' => $parent, 'protocol' => $protocol));
+ }
+ if ($protocol == 'rest') {
+ if (!isset($function['attribs']['type']) ||
+ empty($function['attribs']['type'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_BASEURLTYPE,
+ array('parent' => $parent, 'protocol' => $protocol));
+ }
+ } else {
+ if (!isset($function['attribs']['version']) ||
+ empty($function['attribs']['version'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION,
+ array('parent' => $parent, 'protocol' => $protocol));
+ }
+ }
+ }
+ }
+
+ /**
+ * Test whether a string contains a valid channel server.
+ * @param string $ver the package version to test
+ * @return bool
+ */
+ function validChannelServer($server)
+ {
+ if ($server == '__uri') {
+ return true;
+ }
+ return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server);
+ }
+
+ /**
+ * @return string|false
+ */
+ function getName()
+ {
+ if (isset($this->_channelInfo['name'])) {
+ return $this->_channelInfo['name'];
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @return string|false
+ */
+ function getServer()
+ {
+ if (isset($this->_channelInfo['name'])) {
+ return $this->_channelInfo['name'];
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @return int|80 port number to connect to
+ */
+ function getPort($mirror = false)
+ {
+ if ($mirror) {
+ if ($mir = $this->getMirror($mirror)) {
+ if (isset($mir['attribs']['port'])) {
+ return $mir['attribs']['port'];
+ } else {
+ if ($this->getSSL($mirror)) {
+ return 443;
+ }
+ return 80;
+ }
+ }
+ return false;
+ }
+ if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) {
+ return $this->_channelInfo['servers']['primary']['attribs']['port'];
+ }
+ if ($this->getSSL()) {
+ return 443;
+ }
+ return 80;
+ }
+
+ /**
+ * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel
+ */
+ function getSSL($mirror = false)
+ {
+ if ($mirror) {
+ if ($mir = $this->getMirror($mirror)) {
+ if (isset($mir['attribs']['ssl'])) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return false;
+ }
+ if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return string|false
+ */
+ function getSummary()
+ {
+ if (isset($this->_channelInfo['summary'])) {
+ return $this->_channelInfo['summary'];
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param string xmlrpc or soap
+ * @param string|false mirror name or false for primary server
+ */
+ function getPath($protocol, $mirror = false)
+ {
+ if (!in_array($protocol, array('xmlrpc', 'soap'))) {
+ return false;
+ }
+ if ($mirror) {
+ if (!($mir = $this->getMirror($mirror))) {
+ return false;
+ }
+ if (isset($mir[$protocol]['attribs']['path'])) {
+ return $mir[$protocol]['attribs']['path'];
+ } else {
+ return $protocol . '.php';
+ }
+ } elseif (isset($this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'])) {
+ return $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'];
+ }
+ return $protocol . '.php';
+ }
+
+ /**
+ * @param string protocol type (xmlrpc, soap)
+ * @param string Mirror name
+ * @return array|false
+ */
+ function getFunctions($protocol, $mirror = false)
+ {
+ if ($this->getName() == '__uri') {
+ return false;
+ }
+ if ($protocol == 'rest') {
+ $function = 'baseurl';
+ } else {
+ $function = 'function';
+ }
+ if ($mirror) {
+ if ($mir = $this->getMirror($mirror)) {
+ if (isset($mir[$protocol][$function])) {
+ return $mir[$protocol][$function];
+ }
+ }
+ return false;
+ }
+ if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) {
+ return $this->_channelInfo['servers']['primary'][$protocol][$function];
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param string Protocol type
+ * @param string Function name (null to return the
+ * first protocol of the type requested)
+ * @param string Mirror name, if any
+ * @return array
+ */
+ function getFunction($type, $name = null, $mirror = false)
+ {
+ $protocols = $this->getFunctions($type, $mirror);
+ if (!$protocols) {
+ return false;
+ }
+ foreach ($protocols as $protocol) {
+ if ($name === null) {
+ return $protocol;
+ }
+ if ($protocol['_content'] != $name) {
+ continue;
+ }
+ return $protocol;
+ }
+ return false;
+ }
+
+ /**
+ * @param string protocol type
+ * @param string protocol name
+ * @param string version
+ * @param string mirror name
+ * @return boolean
+ */
+ function supports($type, $name = null, $mirror = false, $version = '1.0')
+ {
+ $protocols = $this->getFunctions($type, $mirror);
+ if (!$protocols) {
+ return false;
+ }
+ foreach ($protocols as $protocol) {
+ if ($protocol['attribs']['version'] != $version) {
+ continue;
+ }
+ if ($name === null) {
+ return true;
+ }
+ if ($protocol['_content'] != $name) {
+ continue;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determines whether a channel supports Representational State Transfer (REST) protocols
+ * for retrieving channel information
+ * @param string
+ * @return bool
+ */
+ function supportsREST($mirror = false)
+ {
+ if ($mirror == $this->_channelInfo['name']) {
+ $mirror = false;
+ }
+ if ($mirror) {
+ if ($mir = $this->getMirror($mirror)) {
+ return isset($mir['rest']);
+ }
+ return false;
+ }
+ return isset($this->_channelInfo['servers']['primary']['rest']);
+ }
+
+ /**
+ * Get the URL to access a base resource.
+ *
+ * Hyperlinks in the returned xml will be used to retrieve the proper information
+ * needed. This allows extreme extensibility and flexibility in implementation
+ * @param string Resource Type to retrieve
+ */
+ function getBaseURL($resourceType, $mirror = false)
+ {
+ if ($mirror == $this->_channelInfo['name']) {
+ $mirror = false;
+ }
+ if ($mirror) {
+ if ($mir = $this->getMirror($mirror)) {
+ $rest = $mir['rest'];
+ } else {
+ return false;
+ }
+ } else {
+ $rest = $this->_channelInfo['servers']['primary']['rest'];
+ }
+ if (!isset($rest['baseurl'][0])) {
+ $rest['baseurl'] = array($rest['baseurl']);
+ }
+ foreach ($rest['baseurl'] as $baseurl) {
+ if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) {
+ return $baseurl['_content'];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Since REST does not implement RPC, provide this as a logical wrapper around
+ * resetFunctions for REST
+ * @param string|false mirror name, if any
+ */
+ function resetREST($mirror = false)
+ {
+ return $this->resetFunctions('rest', $mirror);
+ }
+
+ /**
+ * Empty all protocol definitions
+ * @param string protocol type (xmlrpc, soap)
+ * @param string|false mirror name, if any
+ */
+ function resetFunctions($type, $mirror = false)
+ {
+ if ($mirror) {
+ if (isset($this->_channelInfo['servers']['mirror'])) {
+ $mirrors = $this->_channelInfo['servers']['mirror'];
+ if (!isset($mirrors[0])) {
+ $mirrors = array($mirrors);
+ }
+ foreach ($mirrors as $i => $mir) {
+ if ($mir['attribs']['host'] == $mirror) {
+ if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) {
+ unset($this->_channelInfo['servers']['mirror'][$i][$type]);
+ }
+ return true;
+ }
+ }
+ return false;
+ } else {
+ return false;
+ }
+ } else {
+ if (isset($this->_channelInfo['servers']['primary'][$type])) {
+ unset($this->_channelInfo['servers']['primary'][$type]);
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Set a channel's protocols to the protocols supported by pearweb
+ */
+ function setDefaultPEARProtocols($version = '1.0', $mirror = false)
+ {
+ switch ($version) {
+ case '1.0' :
+ $this->resetFunctions('xmlrpc', $mirror);
+ $this->resetFunctions('soap', $mirror);
+ $this->resetREST($mirror);
+ $this->addFunction('xmlrpc', '1.0', 'logintest', $mirror);
+ $this->addFunction('xmlrpc', '1.0', 'package.listLatestReleases', $mirror);
+ $this->addFunction('xmlrpc', '1.0', 'package.listAll', $mirror);
+ $this->addFunction('xmlrpc', '1.0', 'package.info', $mirror);
+ $this->addFunction('xmlrpc', '1.0', 'package.getDownloadURL', $mirror);
+ $this->addFunction('xmlrpc', '1.1', 'package.getDownloadURL', $mirror);
+ $this->addFunction('xmlrpc', '1.0', 'package.getDepDownloadURL', $mirror);
+ $this->addFunction('xmlrpc', '1.1', 'package.getDepDownloadURL', $mirror);
+ $this->addFunction('xmlrpc', '1.0', 'package.search', $mirror);
+ $this->addFunction('xmlrpc', '1.0', 'channel.listAll', $mirror);
+ return true;
+ break;
+ default :
+ return false;
+ break;
+ }
+ }
+
+ /**
+ * @return array
+ */
+ function getMirrors()
+ {
+ if (isset($this->_channelInfo['servers']['mirror'])) {
+ $mirrors = $this->_channelInfo['servers']['mirror'];
+ if (!isset($mirrors[0])) {
+ $mirrors = array($mirrors);
+ }
+ return $mirrors;
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * Get the unserialized XML representing a mirror
+ * @return array|false
+ */
+ function getMirror($server)
+ {
+ foreach ($this->getMirrors() as $mirror) {
+ if ($mirror['attribs']['host'] == $server) {
+ return $mirror;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param string
+ * @return string|false
+ * @error PEAR_CHANNELFILE_ERROR_NO_NAME
+ * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME
+ */
+ function setName($name)
+ {
+ return $this->setServer($name);
+ }
+
+ /**
+ * Set the socket number (port) that is used to connect to this channel
+ * @param integer
+ * @param string|false name of the mirror server, or false for the primary
+ */
+ function setPort($port, $mirror = false)
+ {
+ if ($mirror) {
+ if (!isset($this->_channelInfo['servers']['mirror'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+ if (isset($this->_channelInfo['servers']['mirror'][0])) {
+ foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+ if ($mirror == $mir['attribs']['host']) {
+ $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port;
+ return true;
+ }
+ }
+ return false;
+ } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+ $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port;
+ $this->_isValid = false;
+ return true;
+ }
+ }
+ $this->_channelInfo['servers']['primary']['attribs']['port'] = $port;
+ $this->_isValid = false;
+ return true;
+ }
+
+ /**
+ * Set the socket number (port) that is used to connect to this channel
+ * @param bool Determines whether to turn on SSL support or turn it off
+ * @param string|false name of the mirror server, or false for the primary
+ */
+ function setSSL($ssl = true, $mirror = false)
+ {
+ if ($mirror) {
+ if (!isset($this->_channelInfo['servers']['mirror'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+ if (isset($this->_channelInfo['servers']['mirror'][0])) {
+ foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+ if ($mirror == $mir['attribs']['host']) {
+ if (!$ssl) {
+ if (isset($this->_channelInfo['servers']['mirror'][$i]
+ ['attribs']['ssl'])) {
+ unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']);
+ }
+ } else {
+ $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes';
+ }
+ return true;
+ }
+ }
+ return false;
+ } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+ if (!$ssl) {
+ if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) {
+ unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']);
+ }
+ } else {
+ $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes';
+ }
+ $this->_isValid = false;
+ return true;
+ }
+ }
+ if ($ssl) {
+ $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes';
+ } else {
+ if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
+ unset($this->_channelInfo['servers']['primary']['attribs']['ssl']);
+ }
+ }
+ $this->_isValid = false;
+ return true;
+ }
+
+ /**
+ * Set the socket number (port) that is used to connect to this channel
+ * @param integer
+ * @param string|false name of the mirror server, or false for the primary
+ */
+ function setPath($protocol, $path, $mirror = false)
+ {
+ if (!in_array($protocol, array('xmlrpc', 'soap'))) {
+ return false;
+ }
+ if ($mirror) {
+ if (!isset($this->_channelInfo['servers']['mirror'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+ if (isset($this->_channelInfo['servers']['mirror'][0])) {
+ foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+ if ($mirror == $mir['attribs']['host']) {
+ $this->_channelInfo['servers']['mirror'][$i][$protocol]['attribs']['path'] =
+ $path;
+ return true;
+ }
+ }
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+ $this->_channelInfo['servers']['mirror'][$protocol]['attribs']['path'] = $path;
+ $this->_isValid = false;
+ return true;
+ }
+ }
+ $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'] = $path;
+ $this->_isValid = false;
+ return true;
+ }
+
+ /**
+ * @param string
+ * @return string|false
+ * @error PEAR_CHANNELFILE_ERROR_NO_SERVER
+ * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER
+ */
+ function setServer($server, $mirror = false)
+ {
+ if (empty($server)) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER);
+ return false;
+ } elseif (!$this->validChannelServer($server)) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
+ array('tag' => 'name', 'name' => $server));
+ return false;
+ }
+ if ($mirror) {
+ $found = false;
+ foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+ if ($mirror == $mir['attribs']['host']) {
+ $found = true;
+ break;
+ }
+ }
+ if (!$found) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+ $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server;
+ return true;
+ }
+ $this->_channelInfo['name'] = $server;
+ return true;
+ }
+
+ /**
+ * @param string
+ * @return boolean success
+ * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY
+ * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY
+ */
+ function setSummary($summary)
+ {
+ if (empty($summary)) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
+ return false;
+ } elseif (strpos(trim($summary), "\n") !== false) {
+ $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
+ array('summary' => $summary));
+ }
+ $this->_channelInfo['summary'] = $summary;
+ return true;
+ }
+
+ /**
+ * @param string
+ * @param boolean determines whether the alias is in channel.xml or local
+ * @return boolean success
+ */
+ function setAlias($alias, $local = false)
+ {
+ if (!$this->validChannelServer($alias)) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
+ array('tag' => 'suggestedalias', 'name' => $alias));
+ return false;
+ }
+ if ($local) {
+ $this->_channelInfo['localalias'] = $alias;
+ } else {
+ $this->_channelInfo['suggestedalias'] = $alias;
+ }
+ return true;
+ }
+
+ /**
+ * @return string
+ */
+ function getAlias()
+ {
+ if (isset($this->_channelInfo['localalias'])) {
+ return $this->_channelInfo['localalias'];
+ }
+ if (isset($this->_channelInfo['suggestedalias'])) {
+ return $this->_channelInfo['suggestedalias'];
+ }
+ if (isset($this->_channelInfo['name'])) {
+ return $this->_channelInfo['name'];
+ }
+ return '';
+ }
+
+ /**
+ * Set the package validation object if it differs from PEAR's default
+ * The class must be includeable via changing _ in the classname to path separator,
+ * but no checking of this is made.
+ * @param string|false pass in false to reset to the default packagename regex
+ * @return boolean success
+ */
+ function setValidationPackage($validateclass, $version)
+ {
+ if (empty($validateclass)) {
+ unset($this->_channelInfo['validatepackage']);
+ }
+ $this->_channelInfo['validatepackage'] = array('_content' => $validateclass);
+ $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version);
+ }
+
+ /**
+ * Add a protocol to the provides section
+ * @param string protocol type
+ * @param string protocol version
+ * @param string protocol name, if any
+ * @param string mirror name, if this is a mirror's protocol
+ * @return bool
+ */
+ function addFunction($type, $version, $name = '', $mirror = false)
+ {
+ if ($mirror) {
+ return $this->addMirrorFunction($mirror, $type, $version, $name);
+ }
+ $set = array('attribs' => array('version' => $version), '_content' => $name);
+ if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) {
+ if (!isset($this->_channelInfo['servers'])) {
+ $this->_channelInfo['servers'] = array('primary' =>
+ array($type => array()));
+ } elseif (!isset($this->_channelInfo['servers']['primary'])) {
+ $this->_channelInfo['servers']['primary'] = array($type => array());
+ }
+ $this->_channelInfo['servers']['primary'][$type]['function'] = $set;
+ $this->_isValid = false;
+ return true;
+ } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) {
+ $this->_channelInfo['servers']['primary'][$type]['function'] = array(
+ $this->_channelInfo['servers']['primary'][$type]['function']);
+ }
+ $this->_channelInfo['servers']['primary'][$type]['function'][] = $set;
+ return true;
+ }
+ /**
+ * Add a protocol to a mirror's provides section
+ * @param string mirror name (server)
+ * @param string protocol type
+ * @param string protocol version
+ * @param string protocol name, if any
+ */
+ function addMirrorFunction($mirror, $type, $version, $name = '')
+ {
+ if (!isset($this->_channelInfo['servers']['mirror'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+ $setmirror = false;
+ if (isset($this->_channelInfo['servers']['mirror'][0])) {
+ foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+ if ($mirror == $mir['attribs']['host']) {
+ $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
+ break;
+ }
+ }
+ } else {
+ if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+ $setmirror = &$this->_channelInfo['servers']['mirror'];
+ }
+ }
+ if (!$setmirror) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+ $set = array('attribs' => array('version' => $version), '_content' => $name);
+ if (!isset($setmirror[$type]['function'])) {
+ $setmirror[$type]['function'] = $set;
+ $this->_isValid = false;
+ return true;
+ } elseif (!isset($setmirror[$type]['function'][0])) {
+ $setmirror[$type]['function'] = array($setmirror[$type]['function']);
+ }
+ $setmirror[$type]['function'][] = $set;
+ $this->_isValid = false;
+ return true;
+ }
+
+ /**
+ * @param string Resource Type this url links to
+ * @param string URL
+ * @param string|false mirror name, if this is not a primary server REST base URL
+ */
+ function setBaseURL($resourceType, $url, $mirror = false)
+ {
+ if ($mirror) {
+ if (!isset($this->_channelInfo['servers']['mirror'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+ $setmirror = false;
+ if (isset($this->_channelInfo['servers']['mirror'][0])) {
+ foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+ if ($mirror == $mir['attribs']['host']) {
+ $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
+ break;
+ }
+ }
+ } else {
+ if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+ $setmirror = &$this->_channelInfo['servers']['mirror'];
+ }
+ }
+ } else {
+ $setmirror = &$this->_channelInfo['servers']['primary'];
+ }
+ $set = array('attribs' => array('type' => $resourceType), '_content' => $url);
+ if (!isset($setmirror['rest'])) {
+ $setmirror['rest'] = array();
+ }
+ if (!isset($setmirror['rest']['baseurl'])) {
+ $setmirror['rest']['baseurl'] = $set;
+ $this->_isValid = false;
+ return true;
+ } elseif (!isset($setmirror['rest']['baseurl'][0])) {
+ $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']);
+ }
+ foreach ($setmirror['rest']['baseurl'] as $i => $url) {
+ if ($url['attribs']['type'] == $resourceType) {
+ $this->_isValid = false;
+ $setmirror['rest']['baseurl'][$i] = $set;
+ return true;
+ }
+ }
+ $setmirror['rest']['baseurl'][] = $set;
+ $this->_isValid = false;
+ return true;
+ }
+
+ /**
+ * @param string mirror server
+ * @param int mirror http port
+ * @return boolean
+ */
+ function addMirror($server, $port = null)
+ {
+ if ($this->_channelInfo['name'] == '__uri') {
+ return false; // the __uri channel cannot have mirrors by definition
+ }
+ $set = array('attribs' => array('host' => $server));
+ if (is_numeric($port)) {
+ $set['attribs']['port'] = $port;
+ }
+ if (!isset($this->_channelInfo['servers']['mirror'])) {
+ $this->_channelInfo['servers']['mirror'] = $set;
+ return true;
+ } else {
+ if (!isset($this->_channelInfo['servers']['mirror'][0])) {
+ $this->_channelInfo['servers']['mirror'] =
+ array($this->_channelInfo['servers']['mirror']);
+ }
+ }
+ $this->_channelInfo['servers']['mirror'][] = $set;
+ return true;
+ }
+
+ /**
+ * Retrieve the name of the validation package for this channel
+ * @return string|false
+ */
+ function getValidationPackage()
+ {
+ if (!$this->_isValid && !$this->validate()) {
+ return false;
+ }
+ if (!isset($this->_channelInfo['validatepackage'])) {
+ return array('attribs' => array('version' => 'default'),
+ '_content' => 'PEAR_Validate');
+ }
+ return $this->_channelInfo['validatepackage'];
+ }
+
+ /**
+ * Retrieve the object that can be used for custom validation
+ * @param string|false the name of the package to validate. If the package is
+ * the channel validation package, PEAR_Validate is returned
+ * @return PEAR_Validate|false false is returned if the validation package
+ * cannot be located
+ */
+ function &getValidationObject($package = false)
+ {
+ if (!class_exists('PEAR_Validate')) {
+ require_once 'PEAR/Validate.php';
+ }
+ if (!$this->_isValid) {
+ if (!$this->validate()) {
+ $a = false;
+ return $a;
+ }
+ }
+ if (isset($this->_channelInfo['validatepackage'])) {
+ if ($package == $this->_channelInfo['validatepackage']) {
+ // channel validation packages are always validated by PEAR_Validate
+ $val = &new PEAR_Validate;
+ return $val;
+ }
+ if (!class_exists(str_replace('.', '_',
+ $this->_channelInfo['validatepackage']['_content']))) {
+ if ($this->isIncludeable(str_replace('_', '/',
+ $this->_channelInfo['validatepackage']['_content']) . '.php')) {
+ include_once str_replace('_', '/',
+ $this->_channelInfo['validatepackage']['_content']) . '.php';
+ $vclass = str_replace('.', '_',
+ $this->_channelInfo['validatepackage']['_content']);
+ $val = &new $vclass;
+ } else {
+ $a = false;
+ return $a;
+ }
+ } else {
+ $vclass = str_replace('.', '_',
+ $this->_channelInfo['validatepackage']['_content']);
+ $val = &new $vclass;
+ }
+ } else {
+ $val = &new PEAR_Validate;
+ }
+ return $val;
+ }
+
+ function isIncludeable($path)
+ {
+ $possibilities = explode(PATH_SEPARATOR, ini_get('include_path'));
+ foreach ($possibilities as $dir) {
+ if (file_exists($dir . DIRECTORY_SEPARATOR . $path)
+ && is_readable($dir . DIRECTORY_SEPARATOR . $path)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This function is used by the channel updater and retrieves a value set by
+ * the registry, or the current time if it has not been set
+ * @return string
+ */
+ function lastModified()
+ {
+ if (isset($this->_channelInfo['_lastmodified'])) {
+ return $this->_channelInfo['_lastmodified'];
+ }
+ return time();
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/ChannelFile/Parser.php b/vendor/library/Excel/phpxls/PEAR/ChannelFile/Parser.php
new file mode 100644
index 0000000..8840243
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/ChannelFile/Parser.php
@@ -0,0 +1,73 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Parser.php,v 1.5 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * base xml parser class
+ */
+require_once 'PEAR/XMLParser.php';
+require_once 'PEAR/ChannelFile.php';
+/**
+ * Parser for channel.xml
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_ChannelFile_Parser extends PEAR_XMLParser
+{
+ var $_config;
+ var $_logger;
+ var $_registry;
+
+ function setConfig(&$c)
+ {
+ $this->_config = &$c;
+ $this->_registry = &$c->getRegistry();
+ }
+
+ function setLogger(&$l)
+ {
+ $this->_logger = &$l;
+ }
+
+ function parse($data, $file)
+ {
+ if (PEAR::isError($err = parent::parse($data, $file))) {
+ return $err;
+ }
+ $ret = new PEAR_ChannelFile;
+ $ret->setConfig($this->_config);
+ if (isset($this->_logger)) {
+ $ret->setLogger($this->_logger);
+ }
+ $ret->fromArray($this->_unserializedData);
+ // make sure the filelist is in the easy to read format needed
+ $ret->flattenFilelist();
+ $ret->setPackagefile($file, $archive);
+ return $ret;
+ }
+}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Command.php b/vendor/library/Excel/phpxls/PEAR/Command.php
new file mode 100644
index 0000000..4e9305b
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command.php
@@ -0,0 +1,416 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Command.php,v 1.39 2008/01/03 20:26:34 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * Needed for error handling
+ */
+require_once 'PEAR.php';
+require_once 'PEAR/Frontend.php';
+require_once 'PEAR/XMLParser.php';
+
+/**
+ * List of commands and what classes they are implemented in.
+ * @var array command => implementing class
+ */
+$GLOBALS['_PEAR_Command_commandlist'] = array();
+
+/**
+ * List of commands and their descriptions
+ * @var array command => description
+ */
+$GLOBALS['_PEAR_Command_commanddesc'] = array();
+
+/**
+ * List of shortcuts to common commands.
+ * @var array shortcut => command
+ */
+$GLOBALS['_PEAR_Command_shortcuts'] = array();
+
+/**
+ * Array of command objects
+ * @var array class => object
+ */
+$GLOBALS['_PEAR_Command_objects'] = array();
+
+/**
+ * PEAR command class, a simple factory class for administrative
+ * commands.
+ *
+ * How to implement command classes:
+ *
+ * - The class must be called PEAR_Command_Nnn, installed in the
+ * "PEAR/Common" subdir, with a method called getCommands() that
+ * returns an array of the commands implemented by the class (see
+ * PEAR/Command/Install.php for an example).
+ *
+ * - The class must implement a run() function that is called with three
+ * params:
+ *
+ * (string) command name
+ * (array) assoc array with options, freely defined by each
+ * command, for example:
+ * array('force' => true)
+ * (array) list of the other parameters
+ *
+ * The run() function returns a PEAR_CommandResponse object. Use
+ * these methods to get information:
+ *
+ * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL)
+ * *_PARTIAL means that you need to issue at least
+ * one more command to complete the operation
+ * (used for example for validation steps).
+ *
+ * string getMessage() Returns a message for the user. Remember,
+ * no HTML or other interface-specific markup.
+ *
+ * If something unexpected happens, run() returns a PEAR error.
+ *
+ * - DON'T OUTPUT ANYTHING! Return text for output instead.
+ *
+ * - DON'T USE HTML! The text you return will be used from both Gtk,
+ * web and command-line interfaces, so for now, keep everything to
+ * plain text.
+ *
+ * - DON'T USE EXIT OR DIE! Always use pear errors. From static
+ * classes do PEAR::raiseError(), from other classes do
+ * $this->raiseError().
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command
+{
+ // {{{ factory()
+
+ /**
+ * Get the right object for executing a command.
+ *
+ * @param string $command The name of the command
+ * @param object $config Instance of PEAR_Config object
+ *
+ * @return object the command object or a PEAR error
+ *
+ * @access public
+ * @static
+ */
+ static function &factory($command, &$config)
+ {
+ if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
+ PEAR_Command::registerCommands();
+ }
+ if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
+ $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
+ }
+ if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
+ $a = PEAR::raiseError("unknown command `$command'");
+ return $a;
+ }
+ $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
+ if (!class_exists($class)) {
+ require_once $GLOBALS['_PEAR_Command_objects'][$class];
+ }
+ if (!class_exists($class)) {
+ $a = PEAR::raiseError("unknown command `$command'");
+ return $a;
+ }
+ $ui =& PEAR_Command::getFrontendObject();
+ $obj = &new $class($ui, $config);
+ return $obj;
+ }
+
+ // }}}
+ // {{{ & getObject()
+ function &getObject($command)
+ {
+ $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
+ if (!class_exists($class)) {
+ require_once $GLOBALS['_PEAR_Command_objects'][$class];
+ }
+ if (!class_exists($class)) {
+ return PEAR::raiseError("unknown command `$command'");
+ }
+ $ui =& PEAR_Command::getFrontendObject();
+ $config = &PEAR_Config::singleton();
+ $obj = &new $class($ui, $config);
+ return $obj;
+ }
+
+ // }}}
+ // {{{ & getFrontendObject()
+
+ /**
+ * Get instance of frontend object.
+ *
+ * @return object|PEAR_Error
+ * @static
+ */
+ static function &getFrontendObject()
+ {
+ $a = &PEAR_Frontend::singleton();
+ return $a;
+ }
+
+ // }}}
+ // {{{ & setFrontendClass()
+
+ /**
+ * Load current frontend class.
+ *
+ * @param string $uiclass Name of class implementing the frontend
+ *
+ * @return object the frontend object, or a PEAR error
+ * @static
+ */
+ static function &setFrontendClass($uiclass)
+ {
+ $a = &PEAR_Frontend::setFrontendClass($uiclass);
+ return $a;
+ }
+
+ // }}}
+ // {{{ setFrontendType()
+
+ /**
+ * Set current frontend.
+ *
+ * @param string $uitype Name of the frontend type (for example "CLI")
+ *
+ * @return object the frontend object, or a PEAR error
+ * @static
+ */
+ static function setFrontendType($uitype)
+ {
+ $uiclass = 'PEAR_Frontend_' . $uitype;
+ return PEAR_Command::setFrontendClass($uiclass);
+ }
+
+ // }}}
+ // {{{ registerCommands()
+
+ /**
+ * Scan through the Command directory looking for classes
+ * and see what commands they implement.
+ *
+ * @param bool (optional) if FALSE (default), the new list of
+ * commands should replace the current one. If TRUE,
+ * new entries will be merged with old.
+ *
+ * @param string (optional) where (what directory) to look for
+ * classes, defaults to the Command subdirectory of
+ * the directory from where this file (__FILE__) is
+ * included.
+ *
+ * @return bool TRUE on success, a PEAR error on failure
+ *
+ * @access public
+ * @static
+ */
+ static function registerCommands($merge = false, $dir = null)
+ {
+ $parser = new PEAR_XMLParser;
+ if ($dir === null) {
+ $dir = dirname(__FILE__) . '/Command';
+ }
+ if (!is_dir($dir)) {
+ return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory");
+ }
+ $dp = @opendir($dir);
+ if (empty($dp)) {
+ return PEAR::raiseError("registerCommands: opendir($dir) failed");
+ }
+ if (!$merge) {
+ $GLOBALS['_PEAR_Command_commandlist'] = array();
+ }
+ while ($entry = readdir($dp)) {
+ if ($entry{0} == '.' || substr($entry, -4) != '.xml') {
+ continue;
+ }
+ $class = "PEAR_Command_".substr($entry, 0, -4);
+ $file = "$dir/$entry";
+ $parser->parse(file_get_contents($file));
+ $implements = $parser->getData();
+ // List of commands
+ if (empty($GLOBALS['_PEAR_Command_objects'][$class])) {
+ $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . substr($entry, 0, -4) .
+ '.php';
+ }
+ foreach ($implements as $command => $desc) {
+ if ($command == 'attribs') {
+ continue;
+ }
+ if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
+ return PEAR::raiseError('Command "' . $command . '" already registered in ' .
+ 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
+ }
+ $GLOBALS['_PEAR_Command_commandlist'][$command] = $class;
+ $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary'];
+ if (isset($desc['shortcut'])) {
+ $shortcut = $desc['shortcut'];
+ if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) {
+ return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' .
+ 'registered to command "' . $command . '" in class "' .
+ $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
+ }
+ $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command;
+ }
+ if (isset($desc['options']) && $desc['options']) {
+ foreach ($desc['options'] as $oname => $option) {
+ if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) {
+ return PEAR::raiseError('Option "' . $oname . '" short option "' .
+ $option['shortopt'] . '" must be ' .
+ 'only 1 character in Command "' . $command . '" in class "' .
+ $class . '"');
+ }
+ }
+ }
+ }
+ }
+ ksort($GLOBALS['_PEAR_Command_shortcuts']);
+ ksort($GLOBALS['_PEAR_Command_commandlist']);
+ @closedir($dp);
+ return true;
+ }
+
+ // }}}
+ // {{{ getCommands()
+
+ /**
+ * Get the list of currently supported commands, and what
+ * classes implement them.
+ *
+ * @return array command => implementing class
+ *
+ * @access public
+ * @static
+ */
+ static function getCommands()
+ {
+ if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
+ PEAR_Command::registerCommands();
+ }
+ return $GLOBALS['_PEAR_Command_commandlist'];
+ }
+
+ // }}}
+ // {{{ getShortcuts()
+
+ /**
+ * Get the list of command shortcuts.
+ *
+ * @return array shortcut => command
+ *
+ * @access public
+ * @static
+ */
+ static function getShortcuts()
+ {
+ if (empty($GLOBALS['_PEAR_Command_shortcuts'])) {
+ PEAR_Command::registerCommands();
+ }
+ return $GLOBALS['_PEAR_Command_shortcuts'];
+ }
+
+ // }}}
+ // {{{ getGetoptArgs()
+
+ /**
+ * Compiles arguments for getopt.
+ *
+ * @param string $command command to get optstring for
+ * @param string $short_args (reference) short getopt format
+ * @param array $long_args (reference) long getopt format
+ *
+ * @return void
+ *
+ * @access public
+ * @static
+ */
+ static function getGetoptArgs($command, &$short_args, &$long_args)
+ {
+ if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
+ PEAR_Command::registerCommands();
+ }
+ if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
+ $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
+ }
+ if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
+ return null;
+ }
+ $obj = &PEAR_Command::getObject($command);
+ return $obj->getGetoptArgs($command, $short_args, $long_args);
+ }
+
+ // }}}
+ // {{{ getDescription()
+
+ /**
+ * Get description for a command.
+ *
+ * @param string $command Name of the command
+ *
+ * @return string command description
+ *
+ * @access public
+ * @static
+ */
+ static function getDescription($command)
+ {
+ if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) {
+ return null;
+ }
+ return $GLOBALS['_PEAR_Command_commanddesc'][$command];
+ }
+
+ // }}}
+ // {{{ getHelp()
+
+ /**
+ * Get help for command.
+ *
+ * @param string $command Name of the command to return help for
+ *
+ * @access public
+ * @static
+ */
+ static function getHelp($command)
+ {
+ $cmds = PEAR_Command::getCommands();
+ if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
+ $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
+ }
+ if (isset($cmds[$command])) {
+ $obj = &PEAR_Command::getObject($command);
+ return $obj->getHelp($command);
+ }
+ return false;
+ }
+ // }}}
+}
+
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Auth.php b/vendor/library/Excel/phpxls/PEAR/Command/Auth.php
new file mode 100644
index 0000000..005235b
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Auth.php
@@ -0,0 +1,203 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Auth.php,v 1.31 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+require_once 'PEAR/Config.php';
+
+/**
+ * PEAR commands for login/logout
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Auth extends PEAR_Command_Common
+{
+ // {{{ properties
+
+ var $commands = array(
+ 'login' => array(
+ 'summary' => 'Connects and authenticates to remote server',
+ 'shortcut' => 'li',
+ 'function' => 'doLogin',
+ 'options' => array(),
+ 'doc' => '
+Log in to a remote channel server. If is not supplied,
+the default channel is used. To use remote functions in the installer
+that require any kind of privileges, you need to log in first. The
+username and password you enter here will be stored in your per-user
+PEAR configuration (~/.pearrc on Unix-like systems). After logging
+in, your username and password will be sent along in subsequent
+operations on the remote server.',
+ ),
+ 'logout' => array(
+ 'summary' => 'Logs out from the remote server',
+ 'shortcut' => 'lo',
+ 'function' => 'doLogout',
+ 'options' => array(),
+ 'doc' => '
+Logs out from the remote server. This command does not actually
+connect to the remote server, it only deletes the stored username and
+password from your user configuration.',
+ )
+
+ );
+
+ // }}}
+
+ // {{{ constructor
+
+ /**
+ * PEAR_Command_Auth constructor.
+ *
+ * @access public
+ */
+ function PEAR_Command_Auth(&$ui, &$config)
+ {
+ parent::PEAR_Command_Common($ui, $config);
+ }
+
+ // }}}
+
+ // {{{ doLogin()
+
+ /**
+ * Execute the 'login' command.
+ *
+ * @param string $command command name
+ *
+ * @param array $options option_name => value
+ *
+ * @param array $params list of additional parameters
+ *
+ * @return bool TRUE on success or
+ * a PEAR error on failure
+ *
+ * @access public
+ */
+ function doLogin($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+
+ // If a parameter is supplied, use that as the channel to log in to
+ if (isset($params[0])) {
+ $channel = $params[0];
+ } else {
+ $channel = $this->config->get('default_channel');
+ }
+
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $this->raiseError($chan);
+ }
+ $server = $this->config->get('preferred_mirror', null, $channel);
+ $remote = &$this->config->getRemote();
+ $username = $this->config->get('username', null, $channel);
+ if (empty($username)) {
+ $username = isset($_ENV['USER']) ? $_ENV['USER'] : null;
+ }
+ $this->ui->outputData("Logging in to $server.", $command);
+
+ list($username, $password) = $this->ui->userDialog(
+ $command,
+ array('Username', 'Password'),
+ array('text', 'password'),
+ array($username, '')
+ );
+ $username = trim($username);
+ $password = trim($password);
+
+ $ourfile = $this->config->getConfFile('user');
+ if (!$ourfile) {
+ $ourfile = $this->config->getConfFile('system');
+ }
+
+ $this->config->set('username', $username, 'user', $channel);
+ $this->config->set('password', $password, 'user', $channel);
+
+ if ($chan->supportsREST()) {
+ $ok = true;
+ } else {
+ $remote->expectError(401);
+ $ok = $remote->call('logintest');
+ $remote->popExpect();
+ }
+ if ($ok === true) {
+ $this->ui->outputData("Logged in.", $command);
+ // avoid changing any temporary settings changed with -d
+ $ourconfig = new PEAR_Config($ourfile, $ourfile);
+ $ourconfig->set('username', $username, 'user', $channel);
+ $ourconfig->set('password', $password, 'user', $channel);
+ $ourconfig->store();
+ } else {
+ return $this->raiseError("Login failed!");
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ doLogout()
+
+ /**
+ * Execute the 'logout' command.
+ *
+ * @param string $command command name
+ *
+ * @param array $options option_name => value
+ *
+ * @param array $params list of additional parameters
+ *
+ * @return bool TRUE on success or
+ * a PEAR error on failure
+ *
+ * @access public
+ */
+ function doLogout($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+ $channel = $this->config->get('default_channel');
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $this->raiseError($chan);
+ }
+ $server = $this->config->get('preferred_mirror');
+ $this->ui->outputData("Logging out from $server.", $command);
+ $this->config->remove('username');
+ $this->config->remove('password');
+ $this->config->store();
+ return true;
+ }
+
+ // }}}
+}
+
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Auth.xml b/vendor/library/Excel/phpxls/PEAR/Command/Auth.xml
new file mode 100644
index 0000000..17e3b34
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Auth.xml
@@ -0,0 +1,26 @@
+
+
+ Connects and authenticates to remote server
+ li
+ doLogin
+
+ <channel name>
+Log in to a remote channel server. <channel name> is not supplied,
+the default channel is used. To use remote functions in the installer
+that require any kind of privileges, you need to log in first. The
+username and password you enter here will be stored in your per-user
+PEAR configuration (~/.pearrc on Unix-like systems). After logging
+in, your username and password will be sent along in subsequent
+operations on the remote server.
+
+
+ Logs out from the remote server
+ lo
+ doLogout
+
+
+Logs out from the remote server. This command does not actually
+connect to the remote server, it only deletes the stored username and
+password from your user configuration.
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Build.php b/vendor/library/Excel/phpxls/PEAR/Command/Build.php
new file mode 100644
index 0000000..d677310
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Build.php
@@ -0,0 +1,104 @@
+
+ * @author Tomas V.V.Cox
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Build.php,v 1.14 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for building extensions.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Tomas V.V.Cox
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Build extends PEAR_Command_Common
+{
+ // {{{ properties
+
+ var $commands = array(
+ 'build' => array(
+ 'summary' => 'Build an Extension From C Source',
+ 'function' => 'doBuild',
+ 'shortcut' => 'b',
+ 'options' => array(),
+ 'doc' => '[package.xml]
+Builds one or more extensions contained in a package.'
+ ),
+ );
+
+ // }}}
+
+ // {{{ constructor
+
+ /**
+ * PEAR_Command_Build constructor.
+ *
+ * @access public
+ */
+ function PEAR_Command_Build(&$ui, &$config)
+ {
+ parent::PEAR_Command_Common($ui, $config);
+ }
+
+ // }}}
+
+ // {{{ doBuild()
+
+ function doBuild($command, $options, $params)
+ {
+ require_once 'PEAR/Builder.php';
+ if (sizeof($params) < 1) {
+ $params[0] = 'package.xml';
+ }
+ $builder = &new PEAR_Builder($this->ui);
+ $this->debug = $this->config->get('verbose');
+ $err = $builder->build($params[0], array(&$this, 'buildCallback'));
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ buildCallback()
+
+ function buildCallback($what, $data)
+ {
+ if (($what == 'cmdoutput' && $this->debug > 1) ||
+ ($what == 'output' && $this->debug > 0)) {
+ $this->ui->outputData(rtrim($data), 'build');
+ }
+ }
+
+ // }}}
+}
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Build.xml b/vendor/library/Excel/phpxls/PEAR/Command/Build.xml
new file mode 100644
index 0000000..ec4e6f5
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Build.xml
@@ -0,0 +1,10 @@
+
+
+ Build an Extension From C Source
+ doBuild
+ b
+
+ [package.xml]
+Builds one or more extensions contained in a package.
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Channels.php b/vendor/library/Excel/phpxls/PEAR/Command/Channels.php
new file mode 100644
index 0000000..5de0d39
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Channels.php
@@ -0,0 +1,737 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Channels.php,v 1.57 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for managing channels.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Command_Channels extends PEAR_Command_Common
+{
+ // {{{ properties
+
+ var $commands = array(
+ 'list-channels' => array(
+ 'summary' => 'List Available Channels',
+ 'function' => 'doList',
+ 'shortcut' => 'lc',
+ 'options' => array(),
+ 'doc' => '
+List all available channels for installation.
+',
+ ),
+ 'update-channels' => array(
+ 'summary' => 'Update the Channel List',
+ 'function' => 'doUpdateAll',
+ 'shortcut' => 'uc',
+ 'options' => array(),
+ 'doc' => '
+List all installed packages in all channels.
+'
+ ),
+ 'channel-delete' => array(
+ 'summary' => 'Remove a Channel From the List',
+ 'function' => 'doDelete',
+ 'shortcut' => 'cde',
+ 'options' => array(),
+ 'doc' => '
+Delete a channel from the registry. You may not
+remove any channel that has installed packages.
+'
+ ),
+ 'channel-add' => array(
+ 'summary' => 'Add a Channel',
+ 'function' => 'doAdd',
+ 'shortcut' => 'ca',
+ 'options' => array(),
+ 'doc' => '
+Add a private channel to the channel list. Note that all
+public channels should be synced using "update-channels".
+Parameter may be either a local file or remote URL to a
+channel.xml.
+'
+ ),
+ 'channel-update' => array(
+ 'summary' => 'Update an Existing Channel',
+ 'function' => 'doUpdate',
+ 'shortcut' => 'cu',
+ 'options' => array(
+ 'force' => array(
+ 'shortopt' => 'f',
+ 'doc' => 'will force download of new channel.xml if an existing channel name is used',
+ ),
+ 'channel' => array(
+ 'shortopt' => 'c',
+ 'arg' => 'CHANNEL',
+ 'doc' => 'will force download of new channel.xml if an existing channel name is used',
+ ),
+),
+ 'doc' => '[|]
+Update a channel in the channel list directly. Note that all
+public channels can be synced using "update-channels".
+Parameter may be a local or remote channel.xml, or the name of
+an existing channel.
+'
+ ),
+ 'channel-info' => array(
+ 'summary' => 'Retrieve Information on a Channel',
+ 'function' => 'doInfo',
+ 'shortcut' => 'ci',
+ 'options' => array(),
+ 'doc' => '
+List the files in an installed package.
+'
+ ),
+ 'channel-alias' => array(
+ 'summary' => 'Specify an alias to a channel name',
+ 'function' => 'doAlias',
+ 'shortcut' => 'cha',
+ 'options' => array(),
+ 'doc' => '
+Specify a specific alias to use for a channel name.
+The alias may not be an existing channel name or
+alias.
+'
+ ),
+ 'channel-discover' => array(
+ 'summary' => 'Initialize a Channel from its server',
+ 'function' => 'doDiscover',
+ 'shortcut' => 'di',
+ 'options' => array(),
+ 'doc' => '[|]
+Initialize a channel from its server and create a local channel.xml.
+If is in the format ":@" then
+ and will be set as the login username/password for
+. Use caution when passing the username/password in this way, as
+it may allow other users on your computer to briefly view your username/
+password via the system\'s process list.
+'
+ ),
+ );
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * PEAR_Command_Registry constructor.
+ *
+ * @access public
+ */
+ function PEAR_Command_Channels(&$ui, &$config)
+ {
+ parent::PEAR_Command_Common($ui, $config);
+ }
+
+ // }}}
+
+ // {{{ doList()
+
+ function _sortChannels($a, $b)
+ {
+ return strnatcasecmp($a->getName(), $b->getName());
+ }
+
+ function doList($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+ $registered = $reg->getChannels();
+ usort($registered, array(&$this, '_sortchannels'));
+ $i = $j = 0;
+ $data = array(
+ 'caption' => 'Registered Channels:',
+ 'border' => true,
+ 'headline' => array('Channel', 'Summary')
+ );
+ foreach ($registered as $channel) {
+ $data['data'][] = array($channel->getName(),
+ $channel->getSummary());
+ }
+ if (count($registered)==0) {
+ $data = '(no registered channels)';
+ }
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ function doUpdateAll($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+ $channels = $reg->getChannels();
+
+ $success = true;
+ foreach ($channels as $channel) {
+ if ($channel->getName() != '__uri') {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $this->doUpdate('channel-update',
+ $options,
+ array($channel->getName()));
+ if (PEAR::isError($err)) {
+ $this->ui->outputData($err->getMessage(), $command);
+ $success = false;
+ } else {
+ $success &= $err;
+ }
+ }
+ }
+ return $success;
+ }
+
+ function doInfo($command, $options, $params)
+ {
+ if (sizeof($params) != 1) {
+ return $this->raiseError("No channel specified");
+ }
+ $reg = &$this->config->getRegistry();
+ $channel = strtolower($params[0]);
+ if ($reg->channelExists($channel)) {
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $this->raiseError($chan);
+ }
+ } else {
+ if (strpos($channel, '://')) {
+ $downloader = &$this->getDownloader();
+ $tmpdir = $this->config->get('temp_dir');
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $loc = $downloader->downloadHttp($channel, $this->ui, $tmpdir);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($loc)) {
+ return $this->raiseError('Cannot open "' . $channel .
+ '" (' . $loc->getMessage() . ')');
+ } else {
+ $contents = implode('', file($loc));
+ }
+ } else {
+ if (file_exists($params[0])) {
+ $fp = fopen($params[0], 'r');
+ if (!$fp) {
+ return $this->raiseError('Cannot open "' . $params[0] . '"');
+ }
+ } else {
+ return $this->raiseError('Unknown channel "' . $channel . '"');
+ }
+ $contents = '';
+ while (!feof($fp)) {
+ $contents .= fread($fp, 1024);
+ }
+ fclose($fp);
+ }
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+ $chan = new PEAR_ChannelFile;
+ $chan->fromXmlString($contents);
+ $chan->validate();
+ if ($errs = $chan->getErrors(true)) {
+ foreach ($errs as $err) {
+ $this->ui->outputData($err['level'] . ': ' . $err['message']);
+ }
+ return $this->raiseError('Channel file "' . $params[0] . '" is not valid');
+ }
+ }
+ if ($chan) {
+ $channel = $chan->getName();
+ $caption = 'Channel ' . $channel . ' Information:';
+ $data1 = array(
+ 'caption' => $caption,
+ 'border' => true);
+ $data1['data']['server'] = array('Name and Server', $chan->getName());
+ if ($chan->getAlias() != $chan->getName()) {
+ $data1['data']['alias'] = array('Alias', $chan->getAlias());
+ }
+ $data1['data']['summary'] = array('Summary', $chan->getSummary());
+ $validate = $chan->getValidationPackage();
+ $data1['data']['vpackage'] = array('Validation Package Name', $validate['_content']);
+ $data1['data']['vpackageversion'] =
+ array('Validation Package Version', $validate['attribs']['version']);
+ $d = array();
+ $d['main'] = $data1;
+
+ $data['data'] = array();
+ $data['caption'] = 'Server Capabilities';
+ $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
+ $capabilities = $chan->getFunctions('xmlrpc');
+ $soaps = $chan->getFunctions('soap');
+ if ($capabilities || $soaps || $chan->supportsREST()) {
+ if ($capabilities) {
+ if (!isset($capabilities[0])) {
+ $capabilities = array($capabilities);
+ }
+ foreach ($capabilities as $protocol) {
+ $data['data'][] = array('xmlrpc', $protocol['attribs']['version'],
+ $protocol['_content']);
+ }
+ }
+ if ($soaps) {
+ if (!isset($soaps[0])) {
+ $soaps = array($soaps);
+ }
+ foreach ($soaps as $protocol) {
+ $data['data'][] = array('soap', $protocol['attribs']['version'],
+ $protocol['_content']);
+ }
+ }
+ if ($chan->supportsREST()) {
+ $funcs = $chan->getFunctions('rest');
+ if (!isset($funcs[0])) {
+ $funcs = array($funcs);
+ }
+ foreach ($funcs as $protocol) {
+ $data['data'][] = array('rest', $protocol['attribs']['type'],
+ $protocol['_content']);
+ }
+ }
+ } else {
+ $data['data'][] = array('No supported protocols');
+ }
+ $d['protocols'] = $data;
+ $data['data'] = array();
+ $mirrors = $chan->getMirrors();
+ if ($mirrors) {
+ $data['caption'] = 'Channel ' . $channel . ' Mirrors:';
+ unset($data['headline']);
+ foreach ($mirrors as $mirror) {
+ $data['data'][] = array($mirror['attribs']['host']);
+ $d['mirrors'] = $data;
+ }
+ foreach ($mirrors as $i => $mirror) {
+ $data['data'] = array();
+ $data['caption'] = 'Mirror ' . $mirror['attribs']['host'] . ' Capabilities';
+ $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
+ $capabilities = $chan->getFunctions('xmlrpc', $mirror['attribs']['host']);
+ $soaps = $chan->getFunctions('soap', $mirror['attribs']['host']);
+ if ($capabilities || $soaps || $chan->supportsREST($mirror['attribs']['host'])) {
+ if ($capabilities) {
+ if (!isset($capabilities[0])) {
+ $capabilities = array($capabilities);
+ }
+ foreach ($capabilities as $protocol) {
+ $data['data'][] = array('xmlrpc', $protocol['attribs']['version'],
+ $protocol['_content']);
+ }
+ }
+ if ($soaps) {
+ if (!isset($soaps[0])) {
+ $soaps = array($soaps);
+ }
+ foreach ($soaps as $protocol) {
+ $data['data'][] = array('soap', $protocol['attribs']['version'],
+ $protocol['_content']);
+ }
+ }
+ if ($chan->supportsREST($mirror['attribs']['host'])) {
+ $funcs = $chan->getFunctions('rest', $mirror['attribs']['host']);
+ if (!isset($funcs[0])) {
+ $funcs = array($funcs);
+ }
+ foreach ($funcs as $protocol) {
+ $data['data'][] = array('rest', $protocol['attribs']['type'],
+ $protocol['_content']);
+ }
+ }
+ } else {
+ $data['data'][] = array('No supported protocols');
+ }
+ $d['mirrorprotocols' . $i] = $data;
+ }
+ }
+ $this->ui->outputData($d, 'channel-info');
+ } else {
+ return $this->raiseError('Serious error: Channel "' . $params[0] .
+ '" has a corrupted registry entry');
+ }
+ }
+
+ // }}}
+
+ function doDelete($command, $options, $params)
+ {
+ if (sizeof($params) != 1) {
+ return $this->raiseError('channel-delete: no channel specified');
+ }
+ $reg = &$this->config->getRegistry();
+ if (!$reg->channelExists($params[0])) {
+ return $this->raiseError('channel-delete: channel "' . $params[0] . '" does not exist');
+ }
+ $channel = $reg->channelName($params[0]);
+ if ($channel == 'pear.php.net') {
+ return $this->raiseError('Cannot delete the pear.php.net channel');
+ }
+ if ($channel == 'pecl.php.net') {
+ return $this->raiseError('Cannot delete the pecl.php.net channel');
+ }
+ if ($channel == '__uri') {
+ return $this->raiseError('Cannot delete the __uri pseudo-channel');
+ }
+ if (PEAR::isError($err = $reg->listPackages($channel))) {
+ return $err;
+ }
+ if (count($err)) {
+ return $this->raiseError('Channel "' . $channel .
+ '" has installed packages, cannot delete');
+ }
+ if (!$reg->deleteChannel($channel)) {
+ return $this->raiseError('Channel "' . $channel . '" deletion failed');
+ } else {
+ $this->config->deleteChannel($channel);
+ $this->ui->outputData('Channel "' . $channel . '" deleted', $command);
+ }
+ }
+
+ function doAdd($command, $options, $params)
+ {
+ if (sizeof($params) != 1) {
+ return $this->raiseError('channel-add: no channel file specified');
+ }
+ if (strpos($params[0], '://')) {
+ $downloader = &$this->getDownloader();
+ $tmpdir = $this->config->get('temp_dir');
+ if (!file_exists($tmpdir)) {
+ require_once 'System.php';
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $err = System::mkdir(array('-p', $tmpdir));
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($err)) {
+ return $this->raiseError('channel-add: temp_dir does not exist: "' .
+ $tmpdir .
+ '" - You can change this location with "pear config-set temp_dir"');
+ }
+ }
+ if (!is_writable($tmpdir)) {
+ return $this->raiseError('channel-add: temp_dir is not writable: "' .
+ $tmpdir .
+ '" - You can change this location with "pear config-set temp_dir"');
+ }
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $loc = $downloader->downloadHttp($params[0], $this->ui, $tmpdir, null, false);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($loc)) {
+ return $this->raiseError('channel-add: Cannot open "' . $params[0] .
+ '" (' . $loc->getMessage() . ')');
+ } else {
+ list($loc, $lastmodified) = $loc;
+ $contents = implode('', file($loc));
+ }
+ } else {
+ $lastmodified = $fp = false;
+ if (file_exists($params[0])) {
+ $fp = fopen($params[0], 'r');
+ }
+ if (!$fp) {
+ return $this->raiseError('channel-add: cannot open "' . $params[0] . '"');
+ }
+ $contents = '';
+ while (!feof($fp)) {
+ $contents .= fread($fp, 1024);
+ }
+ fclose($fp);
+ }
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+ $channel = new PEAR_ChannelFile;
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $result = $channel->fromXmlString($contents);
+ PEAR::staticPopErrorHandling();
+ if (!$result) {
+ $exit = false;
+ if (count($errors = $channel->getErrors(true))) {
+ foreach ($errors as $error) {
+ $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
+ if (!$exit) {
+ $exit = $error['level'] == 'error' ? true : false;
+ }
+ }
+ if ($exit) {
+ return $this->raiseError('channel-add: invalid channel.xml file');
+ }
+ }
+ }
+ $reg = &$this->config->getRegistry();
+ if ($reg->channelExists($channel->getName())) {
+ return $this->raiseError('channel-add: Channel "' . $channel->getName() .
+ '" exists, use channel-update to update entry');
+ }
+ $ret = $reg->addChannel($channel, $lastmodified);
+ if (PEAR::isError($ret)) {
+ return $ret;
+ }
+ if (!$ret) {
+ return $this->raiseError('channel-add: adding Channel "' . $channel->getName() .
+ '" to registry failed');
+ }
+ $this->config->setChannels($reg->listChannels());
+ $this->config->writeConfigFile();
+ $this->ui->outputData('Adding Channel "' . $channel->getName() . '" succeeded', $command);
+ }
+
+ function doUpdate($command, $options, $params)
+ {
+ $tmpdir = $this->config->get('temp_dir');
+ if (!file_exists($tmpdir)) {
+ require_once 'System.php';
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $err = System::mkdir(array('-p', $tmpdir));
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($err)) {
+ return $this->raiseError('channel-add: temp_dir does not exist: "' .
+ $tmpdir .
+ '" - You can change this location with "pear config-set temp_dir"');
+ }
+ }
+ if (!is_writable($tmpdir)) {
+ return $this->raiseError('channel-add: temp_dir is not writable: "' .
+ $tmpdir .
+ '" - You can change this location with "pear config-set temp_dir"');
+ }
+ $reg = &$this->config->getRegistry();
+ if (sizeof($params) != 1) {
+ return $this->raiseError("No channel file specified");
+ }
+ $lastmodified = false;
+ if ((!file_exists($params[0]) || is_dir($params[0]))
+ && $reg->channelExists(strtolower($params[0]))) {
+ $c = $reg->getChannel(strtolower($params[0]));
+ if (PEAR::isError($c)) {
+ return $this->raiseError($c);
+ }
+ $this->ui->outputData("Updating channel \"$params[0]\"", $command);
+ $dl = &$this->getDownloader(array());
+ // if force is specified, use a timestamp of "1" to force retrieval
+ $lastmodified = isset($options['force']) ? false : $c->lastModified();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $contents = $dl->downloadHttp('http://' . $c->getName() . '/channel.xml',
+ $this->ui, $tmpdir, null, $lastmodified);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($contents)) {
+ return $this->raiseError('Cannot retrieve channel.xml for channel "' .
+ $c->getName() . '" (' . $contents->getMessage() . ')');
+ }
+ list($contents, $lastmodified) = $contents;
+ if (!$contents) {
+ $this->ui->outputData("Channel \"$params[0]\" is up to date");
+ return;
+ }
+ $contents = implode('', file($contents));
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+ $channel = new PEAR_ChannelFile;
+ $channel->fromXmlString($contents);
+ if (!$channel->getErrors()) {
+ // security check: is the downloaded file for the channel we got it from?
+ if (strtolower($channel->getName()) != strtolower($c->getName())) {
+ if (isset($options['force'])) {
+ $this->ui->log(0, 'WARNING: downloaded channel definition file' .
+ ' for channel "' . $channel->getName() . '" from channel "' .
+ strtolower($c->getName()) . '"');
+ } else {
+ return $this->raiseError('ERROR: downloaded channel definition file' .
+ ' for channel "' . $channel->getName() . '" from channel "' .
+ strtolower($c->getName()) . '"');
+ }
+ }
+ }
+ } else {
+ if (strpos($params[0], '://')) {
+ $dl = &$this->getDownloader();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $loc = $dl->downloadHttp($params[0],
+ $this->ui, $tmpdir, null, $lastmodified);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($loc)) {
+ return $this->raiseError("Cannot open " . $params[0] .
+ ' (' . $loc->getMessage() . ')');
+ } else {
+ list($loc, $lastmodified) = $loc;
+ $contents = implode('', file($loc));
+ }
+ } else {
+ $fp = false;
+ if (file_exists($params[0])) {
+ $fp = fopen($params[0], 'r');
+ }
+ if (!$fp) {
+ return $this->raiseError("Cannot open " . $params[0]);
+ }
+ $contents = '';
+ while (!feof($fp)) {
+ $contents .= fread($fp, 1024);
+ }
+ fclose($fp);
+ }
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+ $channel = new PEAR_ChannelFile;
+ $channel->fromXmlString($contents);
+ }
+ $exit = false;
+ if (count($errors = $channel->getErrors(true))) {
+ foreach ($errors as $error) {
+ $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
+ if (!$exit) {
+ $exit = $error['level'] == 'error' ? true : false;
+ }
+ }
+ if ($exit) {
+ return $this->raiseError('Invalid channel.xml file');
+ }
+ }
+ if (!$reg->channelExists($channel->getName())) {
+ return $this->raiseError('Error: Channel "' . $channel->getName() .
+ '" does not exist, use channel-add to add an entry');
+ }
+ $ret = $reg->updateChannel($channel, $lastmodified);
+ if (PEAR::isError($ret)) {
+ return $ret;
+ }
+ if (!$ret) {
+ return $this->raiseError('Updating Channel "' . $channel->getName() .
+ '" in registry failed');
+ }
+ $this->config->setChannels($reg->listChannels());
+ $this->config->writeConfigFile();
+ $this->ui->outputData('Update of Channel "' . $channel->getName() . '" succeeded');
+ }
+
+ function &getDownloader()
+ {
+ if (!class_exists('PEAR_Downloader')) {
+ require_once 'PEAR/Downloader.php';
+ }
+ $a = new PEAR_Downloader($this->ui, array(), $this->config);
+ return $a;
+ }
+
+ function doAlias($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+ if (sizeof($params) == 1) {
+ return $this->raiseError('No channel alias specified');
+ }
+ if (sizeof($params) != 2) {
+ return $this->raiseError(
+ 'Invalid format, correct is: channel-alias channel alias');
+ }
+ if (!$reg->channelExists($params[0], true)) {
+ if ($reg->isAlias($params[0])) {
+ $extra = ' (use "channel-alias ' . $reg->channelName($params[0]) . ' ' .
+ strtolower($params[1]) . '")';
+ } else {
+ $extra = '';
+ }
+ return $this->raiseError('"' . $params[0] . '" is not a valid channel' . $extra);
+ }
+ if ($reg->isAlias($params[1])) {
+ return $this->raiseError('Channel "' . $reg->channelName($params[1]) . '" is ' .
+ 'already aliased to "' . strtolower($params[1]) . '", cannot re-alias');
+ }
+ $chan = &$reg->getChannel($params[0]);
+ if (PEAR::isError($chan)) {
+ return $this->raiseError('Corrupt registry? Error retrieving channel "' . $params[0] .
+ '" information (' . $chan->getMessage() . ')');
+ }
+ // make it a local alias
+ if (!$chan->setAlias(strtolower($params[1]), true)) {
+ return $this->raiseError('Alias "' . strtolower($params[1]) .
+ '" is not a valid channel alias');
+ }
+ $reg->updateChannel($chan);
+ $this->ui->outputData('Channel "' . $chan->getName() . '" aliased successfully to "' .
+ strtolower($params[1]) . '"');
+ }
+
+ /**
+ * The channel-discover command
+ *
+ * @param string $command command name
+ * @param array $options option_name => value
+ * @param array $params list of additional parameters.
+ * $params[0] should contain a string with either:
+ * - or
+ * - :@
+ * @return null|PEAR_Error
+ */
+ function doDiscover($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+ if (sizeof($params) != 1) {
+ return $this->raiseError("No channel server specified");
+ }
+
+ // Look for the possible input format ":@"
+ if (preg_match('/^(.+):(.+)@(.+)\\z/', $params[0], $matches)) {
+ $username = $matches[1];
+ $password = $matches[2];
+ $channel = $matches[3];
+ } else {
+ $channel = $params[0];
+ }
+
+ if ($reg->channelExists($channel)) {
+ if ($reg->isAlias($channel)) {
+ return $this->raiseError("A channel alias named \"$channel\" " .
+ 'already exists, aliasing channel "' . $reg->channelName($channel)
+ . '"');
+ } else {
+ return $this->raiseError("Channel \"$channel\" is already initialized");
+ }
+ }
+ $this->pushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $this->doAdd($command, $options, array('http://' . $channel . '/channel.xml'));
+ $this->popErrorHandling();
+ if (PEAR::isError($err)) {
+ return $this->raiseError("Discovery of channel \"$channel\" failed (" .
+ $err->getMessage() . ')');
+ }
+
+ // Store username/password if they were given
+ // Arguably we should do a logintest on the channel here, but since
+ // that's awkward on a REST-based channel (even "pear login" doesn't
+ // do it for those), and XML-RPC is deprecated, it's fairly pointless.
+ if (isset($username)) {
+ $this->config->set('username', $username, 'user', $channel);
+ $this->config->set('password', $password, 'user', $channel);
+ $this->config->store();
+ $this->ui->outputData("Stored login for channel \"$channel\" using username \"$username\"", $command);
+ }
+
+ $this->ui->outputData("Discovery of channel \"$channel\" succeeded", $command);
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Channels.xml b/vendor/library/Excel/phpxls/PEAR/Command/Channels.xml
new file mode 100644
index 0000000..e7c7b7f
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Channels.xml
@@ -0,0 +1,98 @@
+
+
+ List Available Channels
+ doList
+ lc
+
+
+List all available channels for installation.
+
+
+
+ Update the Channel List
+ doUpdateAll
+ uc
+
+
+List all installed packages in all channels.
+
+
+
+ Remove a Channel From the List
+ doDelete
+ cde
+
+ <channel name>
+Delete a channel from the registry. You may not
+remove any channel that has installed packages.
+
+
+
+ Add a Channel
+ doAdd
+ ca
+
+ <channel.xml>
+Add a private channel to the channel list. Note that all
+public channels should be synced using "update-channels".
+Parameter may be either a local file or remote URL to a
+channel.xml.
+
+
+
+ Update an Existing Channel
+ doUpdate
+ cu
+
+
+ f
+ will force download of new channel.xml if an existing channel name is used
+
+
+ c
+ CHANNEL
+ will force download of new channel.xml if an existing channel name is used
+
+
+ [<channel.xml>|<channel name>]
+Update a channel in the channel list directly. Note that all
+public channels can be synced using "update-channels".
+Parameter may be a local or remote channel.xml, or the name of
+an existing channel.
+
+
+
+ Retrieve Information on a Channel
+ doInfo
+ ci
+
+ <package>
+List the files in an installed package.
+
+
+
+ Specify an alias to a channel name
+ doAlias
+ cha
+
+ <channel> <alias>
+Specify a specific alias to use for a channel name.
+The alias may not be an existing channel name or
+alias.
+
+
+
+ Initialize a Channel from its server
+ doDiscover
+ di
+
+ [<channel.xml>|<channel name>]
+Initialize a channel from its server and create a local channel.xml.
+If <channel name> is in the format "<username>:<password>@<channel>" then
+<username> and <password> will be set as the login username/password for
+<channel>. Use caution when passing the username/password in this way, as
+it may allow other users on your computer to briefly view your username/
+password via the system's process list.
+
+
+
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Common.php b/vendor/library/Excel/phpxls/PEAR/Command/Common.php
new file mode 100644
index 0000000..4159540
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Common.php
@@ -0,0 +1,291 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Common.php,v 1.36 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR.php';
+
+/**
+ * PEAR commands base class
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Common extends PEAR
+{
+ // {{{ properties
+
+ /**
+ * PEAR_Config object used to pass user system and configuration
+ * on when executing commands
+ *
+ * @var PEAR_Config
+ */
+ var $config;
+ /**
+ * @var PEAR_Registry
+ * @access protected
+ */
+ var $_registry;
+
+ /**
+ * User Interface object, for all interaction with the user.
+ * @var object
+ */
+ var $ui;
+
+ var $_deps_rel_trans = array(
+ 'lt' => '<',
+ 'le' => '<=',
+ 'eq' => '=',
+ 'ne' => '!=',
+ 'gt' => '>',
+ 'ge' => '>=',
+ 'has' => '=='
+ );
+
+ var $_deps_type_trans = array(
+ 'pkg' => 'package',
+ 'ext' => 'extension',
+ 'php' => 'PHP',
+ 'prog' => 'external program',
+ 'ldlib' => 'external library for linking',
+ 'rtlib' => 'external runtime library',
+ 'os' => 'operating system',
+ 'websrv' => 'web server',
+ 'sapi' => 'SAPI backend'
+ );
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * PEAR_Command_Common constructor.
+ *
+ * @access public
+ */
+ function PEAR_Command_Common(&$ui, &$config)
+ {
+ parent::PEAR();
+ $this->config = &$config;
+ $this->ui = &$ui;
+ }
+
+ // }}}
+
+ // {{{ getCommands()
+
+ /**
+ * Return a list of all the commands defined by this class.
+ * @return array list of commands
+ * @access public
+ */
+ function getCommands()
+ {
+ $ret = array();
+ foreach (array_keys($this->commands) as $command) {
+ $ret[$command] = $this->commands[$command]['summary'];
+ }
+ return $ret;
+ }
+
+ // }}}
+ // {{{ getShortcuts()
+
+ /**
+ * Return a list of all the command shortcuts defined by this class.
+ * @return array shortcut => command
+ * @access public
+ */
+ function getShortcuts()
+ {
+ $ret = array();
+ foreach (array_keys($this->commands) as $command) {
+ if (isset($this->commands[$command]['shortcut'])) {
+ $ret[$this->commands[$command]['shortcut']] = $command;
+ }
+ }
+ return $ret;
+ }
+
+ // }}}
+ // {{{ getOptions()
+
+ function getOptions($command)
+ {
+ $shortcuts = $this->getShortcuts();
+ if (isset($shortcuts[$command])) {
+ $command = $shortcuts[$command];
+ }
+ if (isset($this->commands[$command]) &&
+ isset($this->commands[$command]['options'])) {
+ return $this->commands[$command]['options'];
+ } else {
+ return null;
+ }
+ }
+
+ // }}}
+ // {{{ getGetoptArgs()
+
+ function getGetoptArgs($command, &$short_args, &$long_args)
+ {
+ $short_args = "";
+ $long_args = array();
+ if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) {
+ return;
+ }
+ reset($this->commands[$command]['options']);
+ while (list($option, $info) = each($this->commands[$command]['options'])) {
+ $larg = $sarg = '';
+ if (isset($info['arg'])) {
+ if ($info['arg']{0} == '(') {
+ $larg = '==';
+ $sarg = '::';
+ $arg = substr($info['arg'], 1, -1);
+ } else {
+ $larg = '=';
+ $sarg = ':';
+ $arg = $info['arg'];
+ }
+ }
+ if (isset($info['shortopt'])) {
+ $short_args .= $info['shortopt'] . $sarg;
+ }
+ $long_args[] = $option . $larg;
+ }
+ }
+
+ // }}}
+ // {{{ getHelp()
+ /**
+ * Returns the help message for the given command
+ *
+ * @param string $command The command
+ * @return mixed A fail string if the command does not have help or
+ * a two elements array containing [0]=>help string,
+ * [1]=> help string for the accepted cmd args
+ */
+ function getHelp($command)
+ {
+ $config = &PEAR_Config::singleton();
+ if (!isset($this->commands[$command])) {
+ return "No such command \"$command\"";
+ }
+ $help = null;
+ if (isset($this->commands[$command]['doc'])) {
+ $help = $this->commands[$command]['doc'];
+ }
+ if (empty($help)) {
+ // XXX (cox) Fallback to summary if there is no doc (show both?)
+ if (!isset($this->commands[$command]['summary'])) {
+ return "No help for command \"$command\"";
+ }
+ $help = $this->commands[$command]['summary'];
+ }
+ if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) {
+ foreach($matches[0] as $k => $v) {
+ $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help);
+ }
+ }
+ return array($help, $this->getHelpArgs($command));
+ }
+
+ // }}}
+ // {{{ getHelpArgs()
+ /**
+ * Returns the help for the accepted arguments of a command
+ *
+ * @param string $command
+ * @return string The help string
+ */
+ function getHelpArgs($command)
+ {
+ if (isset($this->commands[$command]['options']) &&
+ count($this->commands[$command]['options']))
+ {
+ $help = "Options:\n";
+ foreach ($this->commands[$command]['options'] as $k => $v) {
+ if (isset($v['arg'])) {
+ if ($v['arg'][0] == '(') {
+ $arg = substr($v['arg'], 1, -1);
+ $sapp = " [$arg]";
+ $lapp = "[=$arg]";
+ } else {
+ $sapp = " $v[arg]";
+ $lapp = "=$v[arg]";
+ }
+ } else {
+ $sapp = $lapp = "";
+ }
+ if (isset($v['shortopt'])) {
+ $s = $v['shortopt'];
+ $help .= " -$s$sapp, --$k$lapp\n";
+ } else {
+ $help .= " --$k$lapp\n";
+ }
+ $p = " ";
+ $doc = rtrim(str_replace("\n", "\n$p", $v['doc']));
+ $help .= " $doc\n";
+ }
+ return $help;
+ }
+ return null;
+ }
+
+ // }}}
+ // {{{ run()
+
+ function run($command, $options, $params)
+ {
+ if (empty($this->commands[$command]['function'])) {
+ // look for shortcuts
+ foreach (array_keys($this->commands) as $cmd) {
+ if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) {
+ if (empty($this->commands[$cmd]['function'])) {
+ return $this->raiseError("unknown command `$command'");
+ } else {
+ $func = $this->commands[$cmd]['function'];
+ }
+ $command = $cmd;
+ break;
+ }
+ }
+ } else {
+ $func = $this->commands[$command]['function'];
+ }
+ return $this->$func($command, $options, $params);
+ }
+
+ // }}}
+}
+
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Config.php b/vendor/library/Excel/phpxls/PEAR/Command/Config.php
new file mode 100644
index 0000000..d8179d3
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Config.php
@@ -0,0 +1,422 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Config.php,v 1.56 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for managing configuration data.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Config extends PEAR_Command_Common
+{
+ // {{{ properties
+
+ var $commands = array(
+ 'config-show' => array(
+ 'summary' => 'Show All Settings',
+ 'function' => 'doConfigShow',
+ 'shortcut' => 'csh',
+ 'options' => array(
+ 'channel' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'show configuration variables for another channel',
+ 'arg' => 'CHAN',
+ ),
+),
+ 'doc' => '[layer]
+Displays all configuration values. An optional argument
+may be used to tell which configuration layer to display. Valid
+configuration layers are "user", "system" and "default". To display
+configurations for different channels, set the default_channel
+configuration variable and run config-show again.
+',
+ ),
+ 'config-get' => array(
+ 'summary' => 'Show One Setting',
+ 'function' => 'doConfigGet',
+ 'shortcut' => 'cg',
+ 'options' => array(
+ 'channel' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'show configuration variables for another channel',
+ 'arg' => 'CHAN',
+ ),
+),
+ 'doc' => ' [layer]
+Displays the value of one configuration parameter. The
+first argument is the name of the parameter, an optional second argument
+may be used to tell which configuration layer to look in. Valid configuration
+layers are "user", "system" and "default". If no layer is specified, a value
+will be picked from the first layer that defines the parameter, in the order
+just specified. The configuration value will be retrieved for the channel
+specified by the default_channel configuration variable.
+',
+ ),
+ 'config-set' => array(
+ 'summary' => 'Change Setting',
+ 'function' => 'doConfigSet',
+ 'shortcut' => 'cs',
+ 'options' => array(
+ 'channel' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'show configuration variables for another channel',
+ 'arg' => 'CHAN',
+ ),
+),
+ 'doc' => ' [layer]
+Sets the value of one configuration parameter. The first argument is
+the name of the parameter, the second argument is the new value. Some
+parameters are subject to validation, and the command will fail with
+an error message if the new value does not make sense. An optional
+third argument may be used to specify in which layer to set the
+configuration parameter. The default layer is "user". The
+configuration value will be set for the current channel, which
+is controlled by the default_channel configuration variable.
+',
+ ),
+ 'config-help' => array(
+ 'summary' => 'Show Information About Setting',
+ 'function' => 'doConfigHelp',
+ 'shortcut' => 'ch',
+ 'options' => array(),
+ 'doc' => '[parameter]
+Displays help for a configuration parameter. Without arguments it
+displays help for all configuration parameters.
+',
+ ),
+ 'config-create' => array(
+ 'summary' => 'Create a Default configuration file',
+ 'function' => 'doConfigCreate',
+ 'shortcut' => 'coc',
+ 'options' => array(
+ 'windows' => array(
+ 'shortopt' => 'w',
+ 'doc' => 'create a config file for a windows install',
+ ),
+ ),
+ 'doc' => '
+Create a default configuration file with all directory configuration
+variables set to subdirectories of , and save it as .
+This is useful especially for creating a configuration file for a remote
+PEAR installation (using the --remoteconfig option of install, upgrade,
+and uninstall).
+',
+ ),
+ );
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * PEAR_Command_Config constructor.
+ *
+ * @access public
+ */
+ function PEAR_Command_Config(&$ui, &$config)
+ {
+ parent::PEAR_Command_Common($ui, $config);
+ }
+
+ // }}}
+
+ // {{{ doConfigShow()
+
+ function doConfigShow($command, $options, $params)
+ {
+ if (is_array($params)) {
+ $layer = isset($params[0]) ? $params[0] : NULL;
+ } else {
+ $layer = NULL;
+ }
+
+ // $params[0] -> the layer
+ if ($error = $this->_checkLayer($layer)) {
+ return $this->raiseError("config-show:$error");
+ }
+ $keys = $this->config->getKeys();
+ sort($keys);
+ $channel = isset($options['channel']) ? $options['channel'] :
+ $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ if (!$reg->channelExists($channel)) {
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+ $data = array('caption' => 'Configuration (channel ' . $channel . '):');
+ foreach ($keys as $key) {
+ $type = $this->config->getType($key);
+ $value = $this->config->get($key, $layer, $channel);
+ if ($type == 'password' && $value) {
+ $value = '********';
+ }
+ if ($value === false) {
+ $value = 'false';
+ } elseif ($value === true) {
+ $value = 'true';
+ }
+ $data['data'][$this->config->getGroup($key)][] = array($this->config->getPrompt($key) , $key, $value);
+ }
+ foreach ($this->config->getLayers() as $layer) {
+ $data['data']['Config Files'][] = array(ucfirst($layer) . ' Configuration File', 'Filename' , $this->config->getConfFile($layer));
+ }
+
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ // }}}
+ // {{{ doConfigGet()
+
+ function doConfigGet($command, $options, $params)
+ {
+ if (!is_array($params)) {
+ $args_cnt = 0;
+ } else {
+ $args_cnt = count($params);
+ }
+
+ switch ($args_cnt) {
+ case 1:
+ $config_key = $params[0];
+ $layer = NULL;
+ break;
+ case 2:
+ $config_key = $params[0];
+ $layer = $params[1];
+ if ($error = $this->_checkLayer($layer)) {
+ return $this->raiseError("config-get:$error");
+ }
+ break;
+ case 0:
+ default:
+ return $this->raiseError("config-get expects 1 or 2 parameters");
+ }
+
+ $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+
+ if (!$reg->channelExists($channel)) {
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+
+ $this->ui->outputData($this->config->get($config_key, $layer, $channel), $command);
+
+ return true;
+ }
+
+ // }}}
+ // {{{ doConfigSet()
+
+ function doConfigSet($command, $options, $params)
+ {
+ // $param[0] -> a parameter to set
+ // $param[1] -> the value for the parameter
+ // $param[2] -> the layer
+ $failmsg = '';
+ if (sizeof($params) < 2 || sizeof($params) > 3) {
+ $failmsg .= "config-set expects 2 or 3 parameters";
+ return PEAR::raiseError($failmsg);
+ }
+ if (isset($params[2]) && ($error = $this->_checkLayer($params[2]))) {
+ $failmsg .= $error;
+ return PEAR::raiseError("config-set:$failmsg");
+ }
+ $channel = isset($options['channel']) ? $options['channel'] :
+ $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ if (!$reg->channelExists($channel)) {
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+ if ($params[0] == 'default_channel') {
+ if (!$reg->channelExists($params[1])) {
+ return $this->raiseError('Channel "' . $params[1] . '" does not exist');
+ }
+ }
+ if (count($params) == 2) {
+ array_push($params, 'user');
+ $layer = 'user';
+ } else {
+ $layer = $params[2];
+ }
+ array_push($params, $channel);
+ if (!call_user_func_array(array(&$this->config, 'set'), $params))
+ {
+ array_pop($params);
+ $failmsg = "config-set (" . implode(", ", $params) . ") failed, channel $channel";
+ } else {
+ $this->config->store($layer);
+ }
+ if ($failmsg) {
+ return $this->raiseError($failmsg);
+ }
+ $this->ui->outputData('config-set succeeded', $command);
+ return true;
+ }
+
+ // }}}
+ // {{{ doConfigHelp()
+
+ function doConfigHelp($command, $options, $params)
+ {
+ if (empty($params)) {
+ $params = $this->config->getKeys();
+ }
+ $data['caption'] = "Config help" . ((count($params) == 1) ? " for $params[0]" : '');
+ $data['headline'] = array('Name', 'Type', 'Description');
+ $data['border'] = true;
+ foreach ($params as $name) {
+ $type = $this->config->getType($name);
+ $docs = $this->config->getDocs($name);
+ if ($type == 'set') {
+ $docs = rtrim($docs) . "\nValid set: " .
+ implode(' ', $this->config->getSetValues($name));
+ }
+ $data['data'][] = array($name, $type, $docs);
+ }
+ $this->ui->outputData($data, $command);
+ }
+
+ // }}}
+ // {{{ doConfigCreate()
+
+ function doConfigCreate($command, $options, $params)
+ {
+ if (count($params) != 2) {
+ return PEAR::raiseError('config-create: must have 2 parameters, root path and ' .
+ 'filename to save as');
+ }
+ $root = $params[0];
+ // Clean up the DIRECTORY_SEPARATOR mess
+ $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
+ $root = preg_replace(array('!\\\\+!', '!/+!', "!$ds2+!"),
+ array('/', '/', '/'),
+ $root);
+ if ($root{0} != '/') {
+ if (isset($options['windows'])) {
+ if (!preg_match('/^[A-Za-z]:/', $root)) {
+ return PEAR::raiseError('Root directory must be an absolute path beginning ' .
+ 'with "\\" or "C:\\", was: "' . $root . '"');
+ }
+ } else {
+ return PEAR::raiseError('Root directory must be an absolute path beginning ' .
+ 'with "/", was: "' . $root . '"');
+ }
+ }
+ $windows = isset($options['windows']);
+ if ($windows) {
+ $root = str_replace('/', '\\', $root);
+ }
+ if (!file_exists($params[1])) {
+ if (!@touch($params[1])) {
+ return PEAR::raiseError('Could not create "' . $params[1] . '"');
+ }
+ }
+ $params[1] = realpath($params[1]);
+ $config = &new PEAR_Config($params[1], '#no#system#config#', false, false);
+ if ($root{strlen($root) - 1} == '/') {
+ $root = substr($root, 0, strlen($root) - 1);
+ }
+ $config->noRegistry();
+ $config->set('php_dir', $windows ? "$root\\pear\\php" : "$root/pear/php", 'user');
+ $config->set('data_dir', $windows ? "$root\\pear\\data" : "$root/pear/data");
+ $config->set('www_dir', $windows ? "$root\\pear\\www" : "$root/pear/www");
+ $config->set('cfg_dir', $windows ? "$root\\pear\\cfg" : "$root/pear/cfg");
+ $config->set('ext_dir', $windows ? "$root\\pear\\ext" : "$root/pear/ext");
+ $config->set('doc_dir', $windows ? "$root\\pear\\docs" : "$root/pear/docs");
+ $config->set('test_dir', $windows ? "$root\\pear\\tests" : "$root/pear/tests");
+ $config->set('cache_dir', $windows ? "$root\\pear\\cache" : "$root/pear/cache");
+ $config->set('download_dir', $windows ? "$root\\pear\\download" : "$root/pear/download");
+ $config->set('temp_dir', $windows ? "$root\\pear\\temp" : "$root/pear/temp");
+ $config->set('bin_dir', $windows ? "$root\\pear" : "$root/pear");
+ $config->writeConfigFile();
+ $this->_showConfig($config);
+ $this->ui->outputData('Successfully created default configuration file "' . $params[1] . '"',
+ $command);
+ }
+
+ // }}}
+
+ function _showConfig(&$config)
+ {
+ $params = array('user');
+ $keys = $config->getKeys();
+ sort($keys);
+ $channel = 'pear.php.net';
+ $data = array('caption' => 'Configuration (channel ' . $channel . '):');
+ foreach ($keys as $key) {
+ $type = $config->getType($key);
+ $value = $config->get($key, 'user', $channel);
+ if ($type == 'password' && $value) {
+ $value = '********';
+ }
+ if ($value === false) {
+ $value = 'false';
+ } elseif ($value === true) {
+ $value = 'true';
+ }
+ $data['data'][$config->getGroup($key)][] =
+ array($config->getPrompt($key) , $key, $value);
+ }
+ foreach ($config->getLayers() as $layer) {
+ $data['data']['Config Files'][] =
+ array(ucfirst($layer) . ' Configuration File', 'Filename' ,
+ $config->getConfFile($layer));
+ }
+
+ $this->ui->outputData($data, 'config-show');
+ return true;
+ }
+ // {{{ _checkLayer()
+
+ /**
+ * Checks if a layer is defined or not
+ *
+ * @param string $layer The layer to search for
+ * @return mixed False on no error or the error message
+ */
+ function _checkLayer($layer = null)
+ {
+ if (!empty($layer) && $layer != 'default') {
+ $layers = $this->config->getLayers();
+ if (!in_array($layer, $layers)) {
+ return " only the layers: \"" . implode('" or "', $layers) . "\" are supported";
+ }
+ }
+ return false;
+ }
+
+ // }}}
+}
+
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Config.xml b/vendor/library/Excel/phpxls/PEAR/Command/Config.xml
new file mode 100644
index 0000000..f64a925
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Config.xml
@@ -0,0 +1,92 @@
+
+
+ Show All Settings
+ doConfigShow
+ csh
+
+
+ c
+ show configuration variables for another channel
+ CHAN
+
+
+ [layer]
+Displays all configuration values. An optional argument
+may be used to tell which configuration layer to display. Valid
+configuration layers are "user", "system" and "default". To display
+configurations for different channels, set the default_channel
+configuration variable and run config-show again.
+
+
+
+ Show One Setting
+ doConfigGet
+ cg
+
+
+ c
+ show configuration variables for another channel
+ CHAN
+
+
+ <parameter> [layer]
+Displays the value of one configuration parameter. The
+first argument is the name of the parameter, an optional second argument
+may be used to tell which configuration layer to look in. Valid configuration
+layers are "user", "system" and "default". If no layer is specified, a value
+will be picked from the first layer that defines the parameter, in the order
+just specified. The configuration value will be retrieved for the channel
+specified by the default_channel configuration variable.
+
+
+
+ Change Setting
+ doConfigSet
+ cs
+
+
+ c
+ show configuration variables for another channel
+ CHAN
+
+
+ <parameter> <value> [layer]
+Sets the value of one configuration parameter. The first argument is
+the name of the parameter, the second argument is the new value. Some
+parameters are subject to validation, and the command will fail with
+an error message if the new value does not make sense. An optional
+third argument may be used to specify in which layer to set the
+configuration parameter. The default layer is "user". The
+configuration value will be set for the current channel, which
+is controlled by the default_channel configuration variable.
+
+
+
+ Show Information About Setting
+ doConfigHelp
+ ch
+
+ [parameter]
+Displays help for a configuration parameter. Without arguments it
+displays help for all configuration parameters.
+
+
+
+ Create a Default configuration file
+ doConfigCreate
+ coc
+
+
+ w
+ create a config file for a windows install
+
+
+ <root path> <filename>
+Create a default configuration file with all directory configuration
+variables set to subdirectories of <root path>, and save it as <filename>.
+This is useful especially for creating a configuration file for a remote
+PEAR installation (using the --remoteconfig option of install, upgrade,
+and uninstall).
+
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Install.php b/vendor/library/Excel/phpxls/PEAR/Command/Install.php
new file mode 100644
index 0000000..fba4382
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Install.php
@@ -0,0 +1,1188 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Install.php,v 1.141 2008/05/13 18:32:29 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for installation or deinstallation/upgrading of
+ * packages.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Install extends PEAR_Command_Common
+{
+ // {{{ properties
+
+ var $commands = array(
+ 'install' => array(
+ 'summary' => 'Install Package',
+ 'function' => 'doInstall',
+ 'shortcut' => 'i',
+ 'options' => array(
+ 'force' => array(
+ 'shortopt' => 'f',
+ 'doc' => 'will overwrite newer installed packages',
+ ),
+ 'loose' => array(
+ 'shortopt' => 'l',
+ 'doc' => 'do not check for recommended dependency version',
+ ),
+ 'nodeps' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'ignore dependencies, install anyway',
+ ),
+ 'register-only' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'do not install files, only register the package as installed',
+ ),
+ 'soft' => array(
+ 'shortopt' => 's',
+ 'doc' => 'soft install, fail silently, or upgrade if already installed',
+ ),
+ 'nobuild' => array(
+ 'shortopt' => 'B',
+ 'doc' => 'don\'t build C extensions',
+ ),
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'request uncompressed files when downloading',
+ ),
+ 'installroot' => array(
+ 'shortopt' => 'R',
+ 'arg' => 'DIR',
+ 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
+ ),
+ 'packagingroot' => array(
+ 'shortopt' => 'P',
+ 'arg' => 'DIR',
+ 'doc' => 'root directory used when packaging files, like RPM packaging',
+ ),
+ 'ignore-errors' => array(
+ 'doc' => 'force install even if there were errors',
+ ),
+ 'alldeps' => array(
+ 'shortopt' => 'a',
+ 'doc' => 'install all required and optional dependencies',
+ ),
+ 'onlyreqdeps' => array(
+ 'shortopt' => 'o',
+ 'doc' => 'install all required dependencies',
+ ),
+ 'offline' => array(
+ 'shortopt' => 'O',
+ 'doc' => 'do not attempt to download any urls or contact channels',
+ ),
+ 'pretend' => array(
+ 'shortopt' => 'p',
+ 'doc' => 'Only list the packages that would be downloaded',
+ ),
+ ),
+ 'doc' => '[channel/] ...
+Installs one or more PEAR packages. You can specify a package to
+install in four ways:
+
+"Package-1.0.tgz" : installs from a local file
+
+"http://example.com/Package-1.0.tgz" : installs from
+anywhere on the net.
+
+"package.xml" : installs the package described in
+package.xml. Useful for testing, or for wrapping a PEAR package in
+another package manager such as RPM.
+
+"Package[-version/state][.tar]" : queries your default channel\'s server
+({config master_server}) and downloads the newest package with
+the preferred quality/state ({config preferred_state}).
+
+To retrieve Package version 1.1, use "Package-1.1," to retrieve
+Package state beta, use "Package-beta." To retrieve an uncompressed
+file, append .tar (make sure there is no file by the same name first)
+
+To download a package from another channel, prefix with the channel name like
+"channel/Package"
+
+More than one package may be specified at once. It is ok to mix these
+four ways of specifying packages.
+'),
+ 'upgrade' => array(
+ 'summary' => 'Upgrade Package',
+ 'function' => 'doInstall',
+ 'shortcut' => 'up',
+ 'options' => array(
+ 'force' => array(
+ 'shortopt' => 'f',
+ 'doc' => 'overwrite newer installed packages',
+ ),
+ 'loose' => array(
+ 'shortopt' => 'l',
+ 'doc' => 'do not check for recommended dependency version',
+ ),
+ 'nodeps' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'ignore dependencies, upgrade anyway',
+ ),
+ 'register-only' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'do not install files, only register the package as upgraded',
+ ),
+ 'nobuild' => array(
+ 'shortopt' => 'B',
+ 'doc' => 'don\'t build C extensions',
+ ),
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'request uncompressed files when downloading',
+ ),
+ 'installroot' => array(
+ 'shortopt' => 'R',
+ 'arg' => 'DIR',
+ 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
+ ),
+ 'ignore-errors' => array(
+ 'doc' => 'force install even if there were errors',
+ ),
+ 'alldeps' => array(
+ 'shortopt' => 'a',
+ 'doc' => 'install all required and optional dependencies',
+ ),
+ 'onlyreqdeps' => array(
+ 'shortopt' => 'o',
+ 'doc' => 'install all required dependencies',
+ ),
+ 'offline' => array(
+ 'shortopt' => 'O',
+ 'doc' => 'do not attempt to download any urls or contact channels',
+ ),
+ 'pretend' => array(
+ 'shortopt' => 'p',
+ 'doc' => 'Only list the packages that would be downloaded',
+ ),
+ ),
+ 'doc' => ' ...
+Upgrades one or more PEAR packages. See documentation for the
+"install" command for ways to specify a package.
+
+When upgrading, your package will be updated if the provided new
+package has a higher version number (use the -f option if you need to
+upgrade anyway).
+
+More than one package may be specified at once.
+'),
+ 'upgrade-all' => array(
+ 'summary' => 'Upgrade All Packages',
+ 'function' => 'doUpgradeAll',
+ 'shortcut' => 'ua',
+ 'options' => array(
+ 'nodeps' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'ignore dependencies, upgrade anyway',
+ ),
+ 'register-only' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'do not install files, only register the package as upgraded',
+ ),
+ 'nobuild' => array(
+ 'shortopt' => 'B',
+ 'doc' => 'don\'t build C extensions',
+ ),
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'request uncompressed files when downloading',
+ ),
+ 'installroot' => array(
+ 'shortopt' => 'R',
+ 'arg' => 'DIR',
+ 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
+ ),
+ 'ignore-errors' => array(
+ 'doc' => 'force install even if there were errors',
+ ),
+ 'loose' => array(
+ 'doc' => 'do not check for recommended dependency version',
+ ),
+ ),
+ 'doc' => '
+Upgrades all packages that have a newer release available. Upgrades are
+done only if there is a release available of the state specified in
+"preferred_state" (currently {config preferred_state}), or a state considered
+more stable.
+'),
+ 'uninstall' => array(
+ 'summary' => 'Un-install Package',
+ 'function' => 'doUninstall',
+ 'shortcut' => 'un',
+ 'options' => array(
+ 'nodeps' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'ignore dependencies, uninstall anyway',
+ ),
+ 'register-only' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'do not remove files, only register the packages as not installed',
+ ),
+ 'installroot' => array(
+ 'shortopt' => 'R',
+ 'arg' => 'DIR',
+ 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
+ ),
+ 'ignore-errors' => array(
+ 'doc' => 'force install even if there were errors',
+ ),
+ 'offline' => array(
+ 'shortopt' => 'O',
+ 'doc' => 'do not attempt to uninstall remotely',
+ ),
+ ),
+ 'doc' => '[channel/] ...
+Uninstalls one or more PEAR packages. More than one package may be
+specified at once. Prefix with channel name to uninstall from a
+channel not in your default channel ({config default_channel})
+'),
+ 'bundle' => array(
+ 'summary' => 'Unpacks a Pecl Package',
+ 'function' => 'doBundle',
+ 'shortcut' => 'bun',
+ 'options' => array(
+ 'destination' => array(
+ 'shortopt' => 'd',
+ 'arg' => 'DIR',
+ 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
+ ),
+ 'force' => array(
+ 'shortopt' => 'f',
+ 'doc' => 'Force the unpacking even if there were errors in the package',
+ ),
+ ),
+ 'doc' => '
+Unpacks a Pecl Package into the selected location. It will download the
+package if needed.
+'),
+ 'run-scripts' => array(
+ 'summary' => 'Run Post-Install Scripts bundled with a package',
+ 'function' => 'doRunScripts',
+ 'shortcut' => 'rs',
+ 'options' => array(
+ ),
+ 'doc' => '
+Run post-installation scripts in package , if any exist.
+'),
+ );
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * PEAR_Command_Install constructor.
+ *
+ * @access public
+ */
+ function PEAR_Command_Install(&$ui, &$config)
+ {
+ parent::PEAR_Command_Common($ui, $config);
+ }
+
+ // }}}
+
+ /**
+ * For unit testing purposes
+ */
+ function &getDownloader(&$ui, $options, &$config)
+ {
+ if (!class_exists('PEAR_Downloader')) {
+ require_once 'PEAR/Downloader.php';
+ }
+ $a = &new PEAR_Downloader($ui, $options, $config);
+ return $a;
+ }
+
+ /**
+ * For unit testing purposes
+ */
+ function &getInstaller(&$ui)
+ {
+ if (!class_exists('PEAR_Installer')) {
+ require_once 'PEAR/Installer.php';
+ }
+ $a = &new PEAR_Installer($ui);
+ return $a;
+ }
+
+ function enableExtension($binaries, $type)
+ {
+ if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
+ return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
+ }
+ $ini = $this->_parseIni($phpini);
+ if (PEAR::isError($ini)) {
+ return $ini;
+ }
+ $line = 0;
+ if ($type == 'extsrc' || $type == 'extbin') {
+ $search = 'extensions';
+ $enable = 'extension';
+ } else {
+ $search = 'zend_extensions';
+ ob_start();
+ phpinfo(INFO_GENERAL);
+ $info = ob_get_contents();
+ ob_end_clean();
+ $debug = function_exists('leak') ? '_debug' : '';
+ $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
+ $enable = 'zend_extension' . $debug . $ts;
+ }
+ foreach ($ini[$search] as $line => $extension) {
+ if (in_array($extension, $binaries, true) || in_array(
+ $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
+ // already enabled - assume if one is, all are
+ return true;
+ }
+ }
+ if ($line) {
+ $newini = array_slice($ini['all'], 0, $line);
+ } else {
+ $newini = array();
+ }
+ foreach ($binaries as $binary) {
+ if ($ini['extension_dir']) {
+ $binary = basename($binary);
+ }
+ $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n");
+ }
+ $newini = array_merge($newini, array_slice($ini['all'], $line));
+ $fp = @fopen($phpini, 'wb');
+ if (!$fp) {
+ return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
+ }
+ foreach ($newini as $line) {
+ fwrite($fp, $line);
+ }
+ fclose($fp);
+ return true;
+ }
+
+ function disableExtension($binaries, $type)
+ {
+ if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
+ return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
+ }
+ $ini = $this->_parseIni($phpini);
+ if (PEAR::isError($ini)) {
+ return $ini;
+ }
+ $line = 0;
+ if ($type == 'extsrc' || $type == 'extbin') {
+ $search = 'extensions';
+ $enable = 'extension';
+ } else {
+ $search = 'zend_extensions';
+ ob_start();
+ phpinfo(INFO_GENERAL);
+ $info = ob_get_contents();
+ ob_end_clean();
+ $debug = function_exists('leak') ? '_debug' : '';
+ $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
+ $enable = 'zend_extension' . $debug . $ts;
+ }
+ $found = false;
+ foreach ($ini[$search] as $line => $extension) {
+ if (in_array($extension, $binaries, true) || in_array(
+ $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
+ $found = true;
+ break;
+ }
+ }
+ if (!$found) {
+ // not enabled
+ return true;
+ }
+ $fp = @fopen($phpini, 'wb');
+ if (!$fp) {
+ return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
+ }
+ if ($line) {
+ $newini = array_slice($ini['all'], 0, $line);
+ // delete the enable line
+ $newini = array_merge($newini, array_slice($ini['all'], $line + 1));
+ } else {
+ $newini = array_slice($ini['all'], 1);
+ }
+ foreach ($newini as $line) {
+ fwrite($fp, $line);
+ }
+ fclose($fp);
+ return true;
+ }
+
+ function _parseIni($filename)
+ {
+ if (file_exists($filename)) {
+ if (filesize($filename) > 300000) {
+ return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting');
+ }
+ ob_start();
+ phpinfo(INFO_GENERAL);
+ $info = ob_get_contents();
+ ob_end_clean();
+ $debug = function_exists('leak') ? '_debug' : '';
+ $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
+ $zend_extension_line = 'zend_extension' . $debug . $ts;
+ $all = @file($filename);
+ if (!$all) {
+ return PEAR::raiseError('php.ini "' . $filename .'" could not be read');
+ }
+ $zend_extensions = $extensions = array();
+ // assume this is right, but pull from the php.ini if it is found
+ $extension_dir = ini_get('extension_dir');
+ foreach ($all as $linenum => $line) {
+ $line = trim($line);
+ if (!$line) {
+ continue;
+ }
+ if ($line[0] == ';') {
+ continue;
+ }
+ if (strtolower(substr($line, 0, 13)) == 'extension_dir') {
+ $line = trim(substr($line, 13));
+ if ($line[0] == '=') {
+ $x = trim(substr($line, 1));
+ $x = explode(';', $x);
+ $extension_dir = str_replace('"', '', array_shift($x));
+ continue;
+ }
+ }
+ if (strtolower(substr($line, 0, 9)) == 'extension') {
+ $line = trim(substr($line, 9));
+ if ($line[0] == '=') {
+ $x = trim(substr($line, 1));
+ $x = explode(';', $x);
+ $extensions[$linenum] = str_replace('"', '', array_shift($x));
+ continue;
+ }
+ }
+ if (strtolower(substr($line, 0, strlen($zend_extension_line))) ==
+ $zend_extension_line) {
+ $line = trim(substr($line, strlen($zend_extension_line)));
+ if ($line[0] == '=') {
+ $x = trim(substr($line, 1));
+ $x = explode(';', $x);
+ $zend_extensions[$linenum] = str_replace('"', '', array_shift($x));
+ continue;
+ }
+ }
+ }
+ return array(
+ 'extensions' => $extensions,
+ 'zend_extensions' => $zend_extensions,
+ 'extension_dir' => $extension_dir,
+ 'all' => $all,
+ );
+ } else {
+ return PEAR::raiseError('php.ini "' . $filename . '" does not exist');
+ }
+ }
+
+ // {{{ doInstall()
+
+ function doInstall($command, $options, $params)
+ {
+ if (!class_exists('PEAR_PackageFile')) {
+ require_once 'PEAR/PackageFile.php';
+ }
+ if (empty($this->installer)) {
+ $this->installer = &$this->getInstaller($this->ui);
+ }
+ if ($command == 'upgrade' || $command == 'upgrade-all') {
+ $options['upgrade'] = true;
+ } else {
+ $packages = $params;
+ }
+ if (isset($options['installroot']) && isset($options['packagingroot'])) {
+ return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
+ }
+ $reg = &$this->config->getRegistry();
+ $instreg = &$reg; // instreg used to check if package is installed
+ if (isset($options['packagingroot']) && !isset($options['upgrade'])) {
+ $packrootphp_dir = $this->installer->_prependPath(
+ $this->config->get('php_dir', null, 'pear.php.net'),
+ $options['packagingroot']);
+ $instreg = new PEAR_Registry($packrootphp_dir); // other instreg!
+
+ if ($this->config->get('verbose') > 2) {
+ $this->ui->outputData('using package root: ' . $options['packagingroot']);
+ }
+ }
+ $abstractpackages = array();
+ $otherpackages = array();
+ // parse params
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ foreach($params as $param) {
+ if (strpos($param, 'http://') === 0) {
+ $otherpackages[] = $param;
+ continue;
+ }
+ if (strpos($param, 'channel://') === false && @file_exists($param)) {
+ if (isset($options['force'])) {
+ $otherpackages[] = $param;
+ continue;
+ }
+ $pkg = new PEAR_PackageFile($this->config);
+ $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING);
+ if (PEAR::isError($pf)) {
+ $otherpackages[] = $param;
+ continue;
+ }
+ if ($reg->packageExists($pf->getPackage(), $pf->getChannel()) &&
+ version_compare($pf->getVersion(),
+ $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel()),
+ '<=')) {
+ if ($this->config->get('verbose')) {
+ $this->ui->outputData('Ignoring installed package ' .
+ $reg->parsedPackageNameToString(
+ array('package' => $pf->getPackage(),
+ 'channel' => $pf->getChannel()), true));
+ }
+ continue;
+ }
+ $otherpackages[] = $param;
+ continue;
+ }
+ $e = $reg->parsePackageName($param, $this->config->get('default_channel'));
+ if (PEAR::isError($e)) {
+ $otherpackages[] = $param;
+ } else {
+ $abstractpackages[] = $e;
+ }
+ }
+ PEAR::staticPopErrorHandling();
+
+ // if there are any local package .tgz or remote static url, we can't
+ // filter. The filter only works for abstract packages
+ if (count($abstractpackages) && !isset($options['force'])) {
+ // when not being forced, only do necessary upgrades/installs
+ if (isset($options['upgrade'])) {
+ $abstractpackages = $this->_filterUptodatePackages($abstractpackages,
+ $command);
+ } else {
+ foreach ($abstractpackages as $i => $package) {
+ if (isset($package['group'])) {
+ // do not filter out install groups
+ continue;
+ }
+ if ($instreg->packageExists($package['package'], $package['channel'])) {
+ if ($this->config->get('verbose')) {
+ $this->ui->outputData('Ignoring installed package ' .
+ $reg->parsedPackageNameToString($package, true));
+ }
+ unset($abstractpackages[$i]);
+ }
+ }
+ }
+ $abstractpackages =
+ array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
+ } elseif (count($abstractpackages)) {
+ $abstractpackages =
+ array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
+ }
+
+
+ $packages = array_merge($abstractpackages, $otherpackages);
+ if (!count($packages)) {
+ $this->ui->outputData('Nothing to ' . $command);
+ return true;
+ }
+
+ $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
+ $errors = array();
+ $binaries = array();
+ $downloaded = array();
+ $downloaded = &$this->downloader->download($packages);
+ if (PEAR::isError($downloaded)) {
+ return $this->raiseError($downloaded);
+ }
+ $errors = $this->downloader->getErrorMsgs();
+ if (count($errors)) {
+ $err = array();
+ $err['data'] = array();
+ foreach ($errors as $error) {
+ $err['data'][] = array($error);
+ }
+ $err['headline'] = 'Install Errors';
+ $this->ui->outputData($err);
+ if (!count($downloaded)) {
+ return $this->raiseError("$command failed");
+ }
+ }
+ $data = array(
+ 'headline' => 'Packages that would be Installed'
+ );
+ if (isset($options['pretend'])) {
+ foreach ($downloaded as $package) {
+ $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
+ }
+ $this->ui->outputData($data, 'pretend');
+ return true;
+ }
+ $this->installer->setOptions($options);
+ $this->installer->sortPackagesForInstall($downloaded);
+ if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
+ $this->raiseError($err->getMessage());
+ return true;
+ }
+ $extrainfo = array();
+ $binaries = array();
+ foreach ($downloaded as $param) {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $info = $this->installer->install($param, $options);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($info)) {
+ $oldinfo = $info;
+ $pkg = &$param->getPackageFile();
+ if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
+ if (!($info = $pkg->installBinary($this->installer))) {
+ $this->ui->outputData('ERROR: ' .$oldinfo->getMessage());
+ continue;
+ }
+ // we just installed a different package than requested,
+ // let's change the param and info so that the rest of this works
+ $param = $info[0];
+ $info = $info[1];
+ }
+ }
+ if (is_array($info)) {
+ if ($param->getPackageType() == 'extsrc' ||
+ $param->getPackageType() == 'extbin' ||
+ $param->getPackageType() == 'zendextsrc' ||
+ $param->getPackageType() == 'zendextbin') {
+ $pkg = &$param->getPackageFile();
+ if ($instbin = $pkg->getInstalledBinary()) {
+ $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel());
+ } else {
+ $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel());
+ }
+
+ foreach ($instpkg->getFilelist() as $name => $atts) {
+ $pinfo = pathinfo($atts['installed_as']);
+ if (!isset($pinfo['extension']) ||
+ in_array($pinfo['extension'], array('c', 'h'))) {
+ continue; // make sure we don't match php_blah.h
+ }
+ if ((strpos($pinfo['basename'], 'php_') === 0 &&
+ $pinfo['extension'] == 'dll') ||
+ // most unices
+ $pinfo['extension'] == 'so' ||
+ // hp-ux
+ $pinfo['extension'] == 'sl') {
+ $binaries[] = array($atts['installed_as'], $pinfo);
+ break;
+ }
+ }
+ if (count($binaries)) {
+ foreach ($binaries as $pinfo) {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType());
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($ret)) {
+ $extrainfo[] = $ret->getMessage();
+ if ($param->getPackageType() == 'extsrc' ||
+ $param->getPackageType() == 'extbin') {
+ $exttype = 'extension';
+ } else {
+ ob_start();
+ phpinfo(INFO_GENERAL);
+ $info = ob_get_contents();
+ ob_end_clean();
+ $debug = function_exists('leak') ? '_debug' : '';
+ $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
+ $exttype = 'zend_extension' . $debug . $ts;
+ }
+ $extrainfo[] = 'You should add "' . $exttype . '=' .
+ $pinfo[1]['basename'] . '" to php.ini';
+ } else {
+ $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() .
+ ' enabled in php.ini';
+ }
+ }
+ }
+ }
+ if ($this->config->get('verbose') > 0) {
+ $channel = $param->getChannel();
+ $label = $reg->parsedPackageNameToString(
+ array(
+ 'channel' => $channel,
+ 'package' => $param->getPackage(),
+ 'version' => $param->getVersion(),
+ ));
+ $out = array('data' => "$command ok: $label");
+ if (isset($info['release_warnings'])) {
+ $out['release_warnings'] = $info['release_warnings'];
+ }
+ $this->ui->outputData($out, $command);
+ if (!isset($options['register-only']) && !isset($options['offline'])) {
+ if ($this->config->isDefinedLayer('ftp')) {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $info = $this->installer->ftpInstall($param);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($info)) {
+ $this->ui->outputData($info->getMessage());
+ $this->ui->outputData("remote install failed: $label");
+ } else {
+ $this->ui->outputData("remote install ok: $label");
+ }
+ }
+ }
+ }
+ $deps = $param->getDeps();
+ if ($deps) {
+ if (isset($deps['group'])) {
+ $groups = $deps['group'];
+ if (!isset($groups[0])) {
+ $groups = array($groups);
+ }
+ foreach ($groups as $group) {
+ if ($group['attribs']['name'] == 'default') {
+ // default group is always installed, unless the user
+ // explicitly chooses to install another group
+ continue;
+ }
+ $extrainfo[] = $param->getPackage() . ': Optional feature ' .
+ $group['attribs']['name'] . ' available (' .
+ $group['attribs']['hint'] . ')';
+ }
+ $extrainfo[] = $param->getPackage() .
+ ': To install optional features use "pear install ' .
+ $reg->parsedPackageNameToString(
+ array('package' => $param->getPackage(),
+ 'channel' => $param->getChannel()), true) .
+ '#featurename"';
+ }
+ }
+ $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel());
+ // $pkg may be NULL if install is a 'fake' install via --packagingroot
+ if (is_object($pkg)) {
+ $pkg->setConfig($this->config);
+ if ($list = $pkg->listPostinstallScripts()) {
+ $pn = $reg->parsedPackageNameToString(array('channel' =>
+ $param->getChannel(), 'package' => $param->getPackage()), true);
+ $extrainfo[] = $pn . ' has post-install scripts:';
+ foreach ($list as $file) {
+ $extrainfo[] = $file;
+ }
+ $extrainfo[] = $param->getPackage() .
+ ': Use "pear run-scripts ' . $pn . '" to finish setup.';
+ $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
+ }
+ }
+ } else {
+ return $this->raiseError("$command failed");
+ }
+ }
+ if (count($extrainfo)) {
+ foreach ($extrainfo as $info) {
+ $this->ui->outputData($info);
+ }
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ doUpgradeAll()
+
+ function doUpgradeAll($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+ $toUpgrade = array();
+ foreach ($reg->listChannels() as $channel) {
+ if ($channel == '__uri') {
+ continue;
+ }
+
+ // parse name with channel
+ foreach ($reg->listPackages($channel) as $name) {
+ $toUpgrade[] = $reg->parsedPackageNameToString(array(
+ 'channel' => $channel,
+ 'package' => $name
+ ));
+ }
+ }
+
+ $err = $this->doInstall('upgrade-all', $options, $toUpgrade);
+ if (PEAR::isError($err)) {
+ $this->ui->outputData($err->getMessage(), $command);
+ }
+ }
+
+ // }}}
+ // {{{ doUninstall()
+
+ function doUninstall($command, $options, $params)
+ {
+ if (empty($this->installer)) {
+ $this->installer = &$this->getInstaller($this->ui);
+ }
+ if (isset($options['remoteconfig'])) {
+ $e = $this->config->readFTPConfigFile($options['remoteconfig']);
+ if (!PEAR::isError($e)) {
+ $this->installer->setConfig($this->config);
+ }
+ }
+ if (sizeof($params) < 1) {
+ return $this->raiseError("Please supply the package(s) you want to uninstall");
+ }
+ $reg = &$this->config->getRegistry();
+ $newparams = array();
+ $binaries = array();
+ $badparams = array();
+ foreach ($params as $pkg) {
+ $channel = $this->config->get('default_channel');
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $parsed = $reg->parsePackageName($pkg, $channel);
+ PEAR::staticPopErrorHandling();
+ if (!$parsed || PEAR::isError($parsed)) {
+ $badparams[] = $pkg;
+ continue;
+ }
+ $package = $parsed['package'];
+ $channel = $parsed['channel'];
+ $info = &$reg->getPackage($package, $channel);
+ if ($info === null &&
+ ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
+ // make sure this isn't a package that has flipped from pear to pecl but
+ // used a package.xml 1.0
+ $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
+ $info = &$reg->getPackage($package, $testc);
+ if ($info !== null) {
+ $channel = $testc;
+ }
+ }
+ if ($info === null) {
+ $badparams[] = $pkg;
+ } else {
+ $newparams[] = &$info;
+ // check for binary packages (this is an alias for those packages if so)
+ if ($installedbinary = $info->getInstalledBinary()) {
+ $this->ui->log('adding binary package ' .
+ $reg->parsedPackageNameToString(array('channel' => $channel,
+ 'package' => $installedbinary), true));
+ $newparams[] = &$reg->getPackage($installedbinary, $channel);
+ }
+ // add the contents of a dependency group to the list of installed packages
+ if (isset($parsed['group'])) {
+ $group = $info->getDependencyGroup($parsed['group']);
+ if ($group) {
+ $installed = $reg->getInstalledGroup($group);
+ if ($installed) {
+ foreach ($installed as $i => $p) {
+ $newparams[] = &$installed[$i];
+ }
+ }
+ }
+ }
+ }
+ }
+ $err = $this->installer->sortPackagesForUninstall($newparams);
+ if (PEAR::isError($err)) {
+ $this->ui->outputData($err->getMessage(), $command);
+ return true;
+ }
+ $params = $newparams;
+ // twist this to use it to check on whether dependent packages are also being uninstalled
+ // for circular dependencies like subpackages
+ $this->installer->setUninstallPackages($newparams);
+ $params = array_merge($params, $badparams);
+ $binaries = array();
+ foreach ($params as $pkg) {
+ $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
+ if ($err = $this->installer->uninstall($pkg, $options)) {
+ $this->installer->popErrorHandling();
+ if (PEAR::isError($err)) {
+ $this->ui->outputData($err->getMessage(), $command);
+ continue;
+ }
+ if ($pkg->getPackageType() == 'extsrc' ||
+ $pkg->getPackageType() == 'extbin' ||
+ $pkg->getPackageType() == 'zendextsrc' ||
+ $pkg->getPackageType() == 'zendextbin') {
+ if ($instbin = $pkg->getInstalledBinary()) {
+ continue; // this will be uninstalled later
+ }
+
+ foreach ($pkg->getFilelist() as $name => $atts) {
+ $pinfo = pathinfo($atts['installed_as']);
+ if (!isset($pinfo['extension']) ||
+ in_array($pinfo['extension'], array('c', 'h'))) {
+ continue; // make sure we don't match php_blah.h
+ }
+ if ((strpos($pinfo['basename'], 'php_') === 0 &&
+ $pinfo['extension'] == 'dll') ||
+ // most unices
+ $pinfo['extension'] == 'so' ||
+ // hp-ux
+ $pinfo['extension'] == 'sl') {
+ $binaries[] = array($atts['installed_as'], $pinfo);
+ break;
+ }
+ }
+ if (count($binaries)) {
+ foreach ($binaries as $pinfo) {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType());
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($ret)) {
+ $extrainfo[] = $ret->getMessage();
+ if ($pkg->getPackageType() == 'extsrc' ||
+ $pkg->getPackageType() == 'extbin') {
+ $exttype = 'extension';
+ } else {
+ ob_start();
+ phpinfo(INFO_GENERAL);
+ $info = ob_get_contents();
+ ob_end_clean();
+ $debug = function_exists('leak') ? '_debug' : '';
+ $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
+ $exttype = 'zend_extension' . $debug . $ts;
+ }
+ $this->ui->outputData('Unable to remove "' . $exttype . '=' .
+ $pinfo[1]['basename'] . '" from php.ini', $command);
+ } else {
+ $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() .
+ ' disabled in php.ini', $command);
+ }
+ }
+ }
+ }
+ $savepkg = $pkg;
+ if ($this->config->get('verbose') > 0) {
+ if (is_object($pkg)) {
+ $pkg = $reg->parsedPackageNameToString($pkg);
+ }
+ $this->ui->outputData("uninstall ok: $pkg", $command);
+ }
+ if (!isset($options['offline']) && is_object($savepkg) &&
+ defined('PEAR_REMOTEINSTALL_OK')) {
+ if ($this->config->isDefinedLayer('ftp')) {
+ $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
+ $info = $this->installer->ftpUninstall($savepkg);
+ $this->installer->popErrorHandling();
+ if (PEAR::isError($info)) {
+ $this->ui->outputData($info->getMessage());
+ $this->ui->outputData("remote uninstall failed: $pkg");
+ } else {
+ $this->ui->outputData("remote uninstall ok: $pkg");
+ }
+ }
+ }
+ } else {
+ $this->installer->popErrorHandling();
+ if (is_object($pkg)) {
+ $pkg = $reg->parsedPackageNameToString($pkg);
+ }
+ return $this->raiseError("uninstall failed: $pkg");
+ }
+ }
+ return true;
+ }
+
+ // }}}
+
+
+ // }}}
+ // {{{ doBundle()
+ /*
+ (cox) It just downloads and untars the package, does not do
+ any check that the PEAR_Installer::_installFile() does.
+ */
+
+ function doBundle($command, $options, $params)
+ {
+ $downloader = &$this->getDownloader($this->ui, array('force' => true, 'nodeps' => true,
+ 'soft' => true, 'downloadonly' => true), $this->config);
+ $reg = &$this->config->getRegistry();
+ if (sizeof($params) < 1) {
+ return $this->raiseError("Please supply the package you want to bundle");
+ }
+
+ if (isset($options['destination'])) {
+ if (!is_dir($options['destination'])) {
+ System::mkdir('-p ' . $options['destination']);
+ }
+ $dest = realpath($options['destination']);
+ } else {
+ $pwd = getcwd();
+ if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) {
+ $dest = $pwd . DIRECTORY_SEPARATOR . 'ext';
+ } else {
+ $dest = $pwd;
+ }
+ }
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $downloader->setDownloadDir($dest);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($err)) {
+ return PEAR::raiseError('download directory "' . $dest .
+ '" is not writeable.');
+ }
+ $result = &$downloader->download(array($params[0]));
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if (!isset($result[0])) {
+ return $this->raiseError('unable to unpack ' . $params[0]);
+ }
+ $pkgfile = &$result[0]->getPackageFile();
+ $pkgname = $pkgfile->getName();
+ $pkgversion = $pkgfile->getVersion();
+
+ // Unpacking -------------------------------------------------
+ $dest .= DIRECTORY_SEPARATOR . $pkgname;
+ $orig = $pkgname . '-' . $pkgversion;
+
+ $tar = &new Archive_Tar($pkgfile->getArchiveFile());
+ if (!$tar->extractModify($dest, $orig)) {
+ return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
+ }
+ $this->ui->outputData("Package ready at '$dest'");
+ // }}}
+ }
+
+ // }}}
+
+ function doRunScripts($command, $options, $params)
+ {
+ if (!isset($params[0])) {
+ return $this->raiseError('run-scripts expects 1 parameter: a package name');
+ }
+ $reg = &$this->config->getRegistry();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($parsed)) {
+ return $this->raiseError($parsed);
+ }
+ $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
+ if (is_object($package)) {
+ $package->setConfig($this->config);
+ $package->runPostinstallScripts();
+ } else {
+ return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
+ }
+ $this->ui->outputData('Install scripts complete', $command);
+ return true;
+ }
+
+ /**
+ * Given a list of packages, filter out those ones that are already up to date
+ *
+ * @param $packages: packages, in parsed array format !
+ * @return list of packages that can be upgraded
+ */
+ function _filterUptodatePackages($packages, $command)
+ {
+ $reg = &$this->config->getRegistry();
+ $latestReleases = array();
+
+ $ret = array();
+ foreach($packages as $package) {
+ if (isset($package['group'])) {
+ $ret[] = $package;
+ continue;
+ }
+ $channel = $package['channel'];
+ $name = $package['package'];
+
+ if (!$reg->packageExists($name, $channel)) {
+ $ret[] = $package;
+ continue;
+ }
+ if (!isset($latestReleases[$channel])) {
+ // fill in cache for this channel
+ $chan = &$reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $this->raiseError($chan);
+ }
+ if ($chan->supportsREST($this->config->get('preferred_mirror',
+ null, $channel)) &&
+ $base = $chan->getBaseURL('REST1.0',
+ $this->config->get('preferred_mirror',
+ null, $channel)))
+ {
+ $dorest = true;
+ } else {
+ $dorest = false;
+ $remote = &$this->config->getRemote($this->config);
+ }
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ if ($dorest) {
+ $rest = &$this->config->getREST('1.0', array());
+ $installed = array_flip($reg->listPackages($channel));
+ $latest = $rest->listLatestUpgrades($base,
+ $this->config->get('preferred_state', null, $channel), $installed,
+ $channel, $reg);
+ } else {
+ $latest = $remote->call("package.listLatestReleases",
+ $this->config->get('preferred_state', null, $channel));
+ unset($remote);
+ }
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($latest)) {
+ $this->ui->outputData('Error getting channel info from ' . $channel .
+ ': ' . $latest->getMessage());
+ continue;
+ }
+
+ $latestReleases[$channel] = array_change_key_case($latest);
+ }
+
+ // check package for latest release
+ if (isset($latestReleases[$channel][strtolower($name)])) {
+ // if not set, up to date
+ $inst_version = $reg->packageInfo($name, 'version', $channel);
+ $channel_version = $latestReleases[$channel][strtolower($name)]['version'];
+ if (version_compare($channel_version, $inst_version, "le")) {
+ // installed version is up-to-date
+ continue;
+ }
+ // maintain BC
+ if ($command == 'upgrade-all') {
+ $this->ui->outputData(array('data' => 'Will upgrade ' .
+ $reg->parsedPackageNameToString($package)), $command);
+ }
+ $ret[] = $package;
+ }
+ }
+
+ return $ret;
+ }
+
+}
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Install.xml b/vendor/library/Excel/phpxls/PEAR/Command/Install.xml
new file mode 100644
index 0000000..94044c2
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Install.xml
@@ -0,0 +1,259 @@
+
+
+ Install Package
+ doInstall
+ i
+
+
+ f
+ will overwrite newer installed packages
+
+
+ l
+ do not check for recommended dependency version
+
+
+ n
+ ignore dependencies, install anyway
+
+
+ r
+ do not install files, only register the package as installed
+
+
+ s
+ soft install, fail silently, or upgrade if already installed
+
+
+ B
+ don't build C extensions
+
+
+ Z
+ request uncompressed files when downloading
+
+
+ R
+ DIR
+ root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM
+
+
+ P
+ DIR
+ root directory used when packaging files, like RPM packaging
+
+
+ force install even if there were errors
+
+
+ a
+ install all required and optional dependencies
+
+
+ o
+ install all required dependencies
+
+
+ O
+ do not attempt to download any urls or contact channels
+
+
+ p
+ Only list the packages that would be downloaded
+
+
+ [channel/]<package> ...
+Installs one or more PEAR packages. You can specify a package to
+install in four ways:
+
+"Package-1.0.tgz" : installs from a local file
+
+"http://example.com/Package-1.0.tgz" : installs from
+anywhere on the net.
+
+"package.xml" : installs the package described in
+package.xml. Useful for testing, or for wrapping a PEAR package in
+another package manager such as RPM.
+
+"Package[-version/state][.tar]" : queries your default channel's server
+({config master_server}) and downloads the newest package with
+the preferred quality/state ({config preferred_state}).
+
+To retrieve Package version 1.1, use "Package-1.1," to retrieve
+Package state beta, use "Package-beta." To retrieve an uncompressed
+file, append .tar (make sure there is no file by the same name first)
+
+To download a package from another channel, prefix with the channel name like
+"channel/Package"
+
+More than one package may be specified at once. It is ok to mix these
+four ways of specifying packages.
+
+
+
+ Upgrade Package
+ doInstall
+ up
+
+
+ f
+ overwrite newer installed packages
+
+
+ l
+ do not check for recommended dependency version
+
+
+ n
+ ignore dependencies, upgrade anyway
+
+
+ r
+ do not install files, only register the package as upgraded
+
+
+ B
+ don't build C extensions
+
+
+ Z
+ request uncompressed files when downloading
+
+
+ R
+ DIR
+ root directory used when installing files (ala PHP's INSTALL_ROOT)
+
+
+ force install even if there were errors
+
+
+ a
+ install all required and optional dependencies
+
+
+ o
+ install all required dependencies
+
+
+ O
+ do not attempt to download any urls or contact channels
+
+
+ p
+ Only list the packages that would be downloaded
+
+
+ <package> ...
+Upgrades one or more PEAR packages. See documentation for the
+"install" command for ways to specify a package.
+
+When upgrading, your package will be updated if the provided new
+package has a higher version number (use the -f option if you need to
+upgrade anyway).
+
+More than one package may be specified at once.
+
+
+
+ Upgrade All Packages
+ doInstall
+ ua
+
+
+ n
+ ignore dependencies, upgrade anyway
+
+
+ r
+ do not install files, only register the package as upgraded
+
+
+ B
+ don't build C extensions
+
+
+ Z
+ request uncompressed files when downloading
+
+
+ R
+ DIR
+ root directory used when installing files (ala PHP's INSTALL_ROOT)
+
+
+ force install even if there were errors
+
+
+ do not check for recommended dependency version
+
+
+
+Upgrades all packages that have a newer release available. Upgrades are
+done only if there is a release available of the state specified in
+"preferred_state" (currently {config preferred_state}), or a state considered
+more stable.
+
+
+
+ Un-install Package
+ doUninstall
+ un
+
+
+ n
+ ignore dependencies, uninstall anyway
+
+
+ r
+ do not remove files, only register the packages as not installed
+
+
+ R
+ DIR
+ root directory used when installing files (ala PHP's INSTALL_ROOT)
+
+
+ force install even if there were errors
+
+
+ O
+ do not attempt to uninstall remotely
+
+
+ [channel/]<package> ...
+Uninstalls one or more PEAR packages. More than one package may be
+specified at once. Prefix with channel name to uninstall from a
+channel not in your default channel ({config default_channel})
+
+
+
+ Unpacks a Pecl Package
+ doBundle
+ bun
+
+
+ d
+ DIR
+ Optional destination directory for unpacking (defaults to current path or "ext" if exists)
+
+
+ f
+ Force the unpacking even if there were errors in the package
+
+
+ <package>
+Unpacks a Pecl Package into the selected location. It will download the
+package if needed.
+
+
+
+ Run Post-Install Scripts bundled with a package
+ doRunScripts
+ rs
+
+ <package>
+Run post-installation scripts in package <package>, if any exist.
+
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Mirror.php b/vendor/library/Excel/phpxls/PEAR/Command/Mirror.php
new file mode 100644
index 0000000..f1256e0
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Mirror.php
@@ -0,0 +1,153 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Mirror.php,v 1.20 2008/04/11 01:16:40 dufuz Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.2.0
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for providing file mirrors
+ *
+ * @category pear
+ * @package PEAR
+ * @author Alexander Merz
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.2.0
+ */
+class PEAR_Command_Mirror extends PEAR_Command_Common
+{
+ // {{{ properties
+
+ var $commands = array(
+ 'download-all' => array(
+ 'summary' => 'Downloads each available package from the default channel',
+ 'function' => 'doDownloadAll',
+ 'shortcut' => 'da',
+ 'options' => array(
+ 'channel' =>
+ array(
+ 'shortopt' => 'c',
+ 'doc' => 'specify a channel other than the default channel',
+ 'arg' => 'CHAN',
+ ),
+ ),
+ 'doc' => '
+Requests a list of available packages from the default channel ({config default_channel})
+and downloads them to current working directory. Note: only
+packages within preferred_state ({config preferred_state}) will be downloaded'
+ ),
+ );
+
+ // }}}
+
+ // {{{ constructor
+
+ /**
+ * PEAR_Command_Mirror constructor.
+ *
+ * @access public
+ * @param object PEAR_Frontend a reference to an frontend
+ * @param object PEAR_Config a reference to the configuration data
+ */
+ function PEAR_Command_Mirror(&$ui, &$config)
+ {
+ parent::PEAR_Command_Common($ui, $config);
+ }
+
+ // }}}
+
+ /**
+ * For unit-testing
+ */
+ function &factory($a)
+ {
+ $a = &PEAR_Command::factory($a, $this->config);
+ return $a;
+ }
+
+ // {{{ doDownloadAll()
+ /**
+ * retrieves a list of avaible Packages from master server
+ * and downloads them
+ *
+ * @access public
+ * @param string $command the command
+ * @param array $options the command options before the command
+ * @param array $params the stuff after the command name
+ * @return bool true if succesful
+ * @throw PEAR_Error
+ */
+ function doDownloadAll($command, $options, $params)
+ {
+ $savechannel = $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ $channel = isset($options['channel']) ? $options['channel'] :
+ $this->config->get('default_channel');
+ if (!$reg->channelExists($channel)) {
+ $this->config->set('default_channel', $savechannel);
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+ $this->config->set('default_channel', $channel);
+ $this->ui->outputData('Using Channel ' . $this->config->get('default_channel'));
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $this->raiseError($chan);
+ }
+ if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+ $rest = &$this->config->getREST('1.0', array());
+ $remoteInfo = array_flip($rest->listPackages($base, $channel));
+ } else {
+ $remote = &$this->config->getRemote();
+ $stable = ($this->config->get('preferred_state') == 'stable');
+ $remoteInfo = $remote->call("package.listAll", true, $stable, false);
+ }
+ if (PEAR::isError($remoteInfo)) {
+ return $remoteInfo;
+ }
+ $cmd = &$this->factory("download");
+ if (PEAR::isError($cmd)) {
+ return $cmd;
+ }
+ $this->ui->outputData('Using Preferred State of ' .
+ $this->config->get('preferred_state'));
+ $this->ui->outputData('Gathering release information, please wait...');
+ /**
+ * Error handling not necessary, because already done by
+ * the download command
+ */
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $cmd->run('download', array('downloadonly' => true), array_keys($remoteInfo));
+ PEAR::staticPopErrorHandling();
+ $this->config->set('default_channel', $savechannel);
+ if (PEAR::isError($err)) {
+ $this->ui->outputData($err->getMessage());
+ }
+ return true;
+ }
+
+ // }}}
+}
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Mirror.xml b/vendor/library/Excel/phpxls/PEAR/Command/Mirror.xml
new file mode 100644
index 0000000..fe8be9d
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Mirror.xml
@@ -0,0 +1,18 @@
+
+
+ Downloads each available package from the default channel
+ doDownloadAll
+ da
+
+
+ c
+ specify a channel other than the default channel
+ CHAN
+
+
+
+Requests a list of available packages from the default channel ({config default_channel})
+and downloads them to current working directory. Note: only
+packages within preferred_state ({config preferred_state}) will be downloaded
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Package.php b/vendor/library/Excel/phpxls/PEAR/Command/Package.php
new file mode 100644
index 0000000..8eb16df
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Package.php
@@ -0,0 +1,843 @@
+
+ * @author Martin Jansen
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Package.php,v 1.128 2008/03/29 21:06:58 dufuz Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for login/logout
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Martin Jansen
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+
+class PEAR_Command_Package extends PEAR_Command_Common
+{
+ // {{{ properties
+
+ var $commands = array(
+ 'package' => array(
+ 'summary' => 'Build Package',
+ 'function' => 'doPackage',
+ 'shortcut' => 'p',
+ 'options' => array(
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'Do not gzip the package file'
+ ),
+ 'showname' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'Print the name of the packaged file.',
+ ),
+ ),
+ 'doc' => '[descfile] [descfile2]
+Creates a PEAR package from its description file (usually called
+package.xml). If a second packagefile is passed in, then
+the packager will check to make sure that one is a package.xml
+version 1.0, and the other is a package.xml version 2.0. The
+package.xml version 1.0 will be saved as "package.xml" in the archive,
+and the other as "package2.xml" in the archive"
+'
+ ),
+ 'package-validate' => array(
+ 'summary' => 'Validate Package Consistency',
+ 'function' => 'doPackageValidate',
+ 'shortcut' => 'pv',
+ 'options' => array(),
+ 'doc' => '
+',
+ ),
+ 'cvsdiff' => array(
+ 'summary' => 'Run a "cvs diff" for all files in a package',
+ 'function' => 'doCvsDiff',
+ 'shortcut' => 'cd',
+ 'options' => array(
+ 'quiet' => array(
+ 'shortopt' => 'q',
+ 'doc' => 'Be quiet',
+ ),
+ 'reallyquiet' => array(
+ 'shortopt' => 'Q',
+ 'doc' => 'Be really quiet',
+ ),
+ 'date' => array(
+ 'shortopt' => 'D',
+ 'doc' => 'Diff against revision of DATE',
+ 'arg' => 'DATE',
+ ),
+ 'release' => array(
+ 'shortopt' => 'R',
+ 'doc' => 'Diff against tag for package release REL',
+ 'arg' => 'REL',
+ ),
+ 'revision' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'Diff against revision REV',
+ 'arg' => 'REV',
+ ),
+ 'context' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'Generate context diff',
+ ),
+ 'unified' => array(
+ 'shortopt' => 'u',
+ 'doc' => 'Generate unified diff',
+ ),
+ 'ignore-case' => array(
+ 'shortopt' => 'i',
+ 'doc' => 'Ignore case, consider upper- and lower-case letters equivalent',
+ ),
+ 'ignore-whitespace' => array(
+ 'shortopt' => 'b',
+ 'doc' => 'Ignore changes in amount of white space',
+ ),
+ 'ignore-blank-lines' => array(
+ 'shortopt' => 'B',
+ 'doc' => 'Ignore changes that insert or delete blank lines',
+ ),
+ 'brief' => array(
+ 'doc' => 'Report only whether the files differ, no details',
+ ),
+ 'dry-run' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'Don\'t do anything, just pretend',
+ ),
+ ),
+ 'doc' => '
+Compares all the files in a package. Without any options, this
+command will compare the current code with the last checked-in code.
+Using the -r or -R option you may compare the current code with that
+of a specific release.
+',
+ ),
+ 'cvstag' => array(
+ 'summary' => 'Set CVS Release Tag',
+ 'function' => 'doCvsTag',
+ 'shortcut' => 'ct',
+ 'options' => array(
+ 'quiet' => array(
+ 'shortopt' => 'q',
+ 'doc' => 'Be quiet',
+ ),
+ 'reallyquiet' => array(
+ 'shortopt' => 'Q',
+ 'doc' => 'Be really quiet',
+ ),
+ 'slide' => array(
+ 'shortopt' => 'F',
+ 'doc' => 'Move (slide) tag if it exists',
+ ),
+ 'delete' => array(
+ 'shortopt' => 'd',
+ 'doc' => 'Remove tag',
+ ),
+ 'dry-run' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'Don\'t do anything, just pretend',
+ ),
+ ),
+ 'doc' => ' [files...]
+Sets a CVS tag on all files in a package. Use this command after you have
+packaged a distribution tarball with the "package" command to tag what
+revisions of what files were in that release. If need to fix something
+after running cvstag once, but before the tarball is released to the public,
+use the "slide" option to move the release tag.
+
+to include files (such as a second package.xml, or tests not included in the
+release), pass them as additional parameters.
+',
+ ),
+ 'package-dependencies' => array(
+ 'summary' => 'Show package dependencies',
+ 'function' => 'doPackageDependencies',
+ 'shortcut' => 'pd',
+ 'options' => array(),
+ 'doc' => '
+List all dependencies the package has.'
+ ),
+ 'sign' => array(
+ 'summary' => 'Sign a package distribution file',
+ 'function' => 'doSign',
+ 'shortcut' => 'si',
+ 'options' => array(
+ 'verbose' => array(
+ 'shortopt' => 'v',
+ 'doc' => 'Display GnuPG output',
+ ),
+ ),
+ 'doc' => '
+Signs a package distribution (.tar or .tgz) file with GnuPG.',
+ ),
+ 'makerpm' => array(
+ 'summary' => 'Builds an RPM spec file from a PEAR package',
+ 'function' => 'doMakeRPM',
+ 'shortcut' => 'rpm',
+ 'options' => array(
+ 'spec-template' => array(
+ 'shortopt' => 't',
+ 'arg' => 'FILE',
+ 'doc' => 'Use FILE as RPM spec file template'
+ ),
+ 'rpm-pkgname' => array(
+ 'shortopt' => 'p',
+ 'arg' => 'FORMAT',
+ 'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced
+by the PEAR package name, defaults to "PEAR::%s".',
+ ),
+ ),
+ 'doc' => '
+
+Creates an RPM .spec file for wrapping a PEAR package inside an RPM
+package. Intended to be used from the SPECS directory, with the PEAR
+package tarball in the SOURCES directory:
+
+$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
+Wrote RPM spec file PEAR::Net_Geo-1.0.spec
+$ rpm -bb PEAR::Net_Socket-1.0.spec
+...
+Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
+',
+ ),
+ 'convert' => array(
+ 'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format',
+ 'function' => 'doConvert',
+ 'shortcut' => 'c2',
+ 'options' => array(
+ 'flat' => array(
+ 'shortopt' => 'f',
+ 'doc' => 'do not beautify the filelist.',
+ ),
+ ),
+ 'doc' => '[descfile] [descfile2]
+Converts a package.xml in 1.0 format into a package.xml
+in 2.0 format. The new file will be named package2.xml by default,
+and package.xml will be used as the old file by default.
+This is not the most intelligent conversion, and should only be
+used for automated conversion or learning the format.
+'
+ ),
+ );
+
+ var $output;
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * PEAR_Command_Package constructor.
+ *
+ * @access public
+ */
+ function PEAR_Command_Package(&$ui, &$config)
+ {
+ parent::PEAR_Command_Common($ui, $config);
+ }
+
+ // }}}
+
+ // {{{ _displayValidationResults()
+
+ function _displayValidationResults($err, $warn, $strict = false)
+ {
+ foreach ($err as $e) {
+ $this->output .= "Error: $e\n";
+ }
+ foreach ($warn as $w) {
+ $this->output .= "Warning: $w\n";
+ }
+ $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n",
+ sizeof($err), sizeof($warn));
+ if ($strict && sizeof($err) > 0) {
+ $this->output .= "Fix these errors and try again.";
+ return false;
+ }
+ return true;
+ }
+
+ // }}}
+ function &getPackager()
+ {
+ if (!class_exists('PEAR_Packager')) {
+ require_once 'PEAR/Packager.php';
+ }
+ $a = &new PEAR_Packager;
+ return $a;
+ }
+
+ function &getPackageFile($config, $debug = false, $tmpdir = null)
+ {
+ if (!class_exists('PEAR_Common')) {
+ require_once 'PEAR/Common.php';
+ }
+ if (!class_exists('PEAR_PackageFile')) {
+ require_once 'PEAR/PackageFile.php';
+ }
+ $a = &new PEAR_PackageFile($config, $debug, $tmpdir);
+ $common = new PEAR_Common;
+ $common->ui = $this->ui;
+ $a->setLogger($common);
+ return $a;
+ }
+ // {{{ doPackage()
+
+ function doPackage($command, $options, $params)
+ {
+ $this->output = '';
+ $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml';
+ $pkg2 = isset($params[1]) ? $params[1] : null;
+ if (!$pkg2 && !isset($params[0])) {
+ if (file_exists('package2.xml')) {
+ $pkg2 = 'package2.xml';
+ }
+ }
+ $packager = &$this->getPackager();
+ $compress = empty($options['nocompress']) ? true : false;
+ $result = $packager->package($pkginfofile, $compress, $pkg2);
+ if (PEAR::isError($result)) {
+ return $this->raiseError($result);
+ }
+ // Don't want output, only the package file name just created
+ if (isset($options['showname'])) {
+ $this->output = $result;
+ }
+ if ($this->output) {
+ $this->ui->outputData($this->output, $command);
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ doPackageValidate()
+
+ function doPackageValidate($command, $options, $params)
+ {
+ $this->output = '';
+ if (sizeof($params) < 1) {
+ $params[0] = "package.xml";
+ }
+ $obj = &$this->getPackageFile($this->config, $this->_debug);
+ $obj->rawReturn();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($info)) {
+ $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL);
+ } else {
+ $archive = $info->getArchiveFile();
+ $tar = &new Archive_Tar($archive);
+ $tar->extract(dirname($info->getPackageFile()));
+ $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR .
+ $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR .
+ basename($info->getPackageFile()));
+ }
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+ $valid = false;
+ if ($info->getPackagexmlVersion() == '2.0') {
+ if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) {
+ $info->flattenFileList();
+ $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
+ }
+ } else {
+ $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
+ }
+ $err = $warn = array();
+ if ($errors = $info->getValidationWarnings()) {
+ foreach ($errors as $error) {
+ if ($error['level'] == 'warning') {
+ $warn[] = $error['message'];
+ } else {
+ $err[] = $error['message'];
+ }
+ }
+ }
+ $this->_displayValidationResults($err, $warn);
+ $this->ui->outputData($this->output, $command);
+ return true;
+ }
+
+ // }}}
+ // {{{ doCvsTag()
+
+ function doCvsTag($command, $options, $params)
+ {
+ $this->output = '';
+ $_cmd = $command;
+ if (sizeof($params) < 1) {
+ $help = $this->getHelp($command);
+ return $this->raiseError("$command: missing parameter: $help[0]");
+ }
+ $obj = &$this->getPackageFile($this->config, $this->_debug);
+ $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+ $err = $warn = array();
+ if (!$info->validate()) {
+ foreach ($info->getValidationWarnings() as $error) {
+ if ($error['level'] == 'warning') {
+ $warn[] = $error['message'];
+ } else {
+ $err[] = $error['message'];
+ }
+ }
+ }
+ if (!$this->_displayValidationResults($err, $warn, true)) {
+ $this->ui->outputData($this->output, $command);
+ return $this->raiseError('CVS tag failed');
+ }
+ $version = $info->getVersion();
+ $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version);
+ $cvstag = "RELEASE_$cvsversion";
+ $files = array_keys($info->getFilelist());
+ $command = "cvs";
+ if (isset($options['quiet'])) {
+ $command .= ' -q';
+ }
+ if (isset($options['reallyquiet'])) {
+ $command .= ' -Q';
+ }
+ $command .= ' tag';
+ if (isset($options['slide'])) {
+ $command .= ' -F';
+ }
+ if (isset($options['delete'])) {
+ $command .= ' -d';
+ }
+ $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]);
+ array_shift($params);
+ if (count($params)) {
+ // add in additional files to be tagged
+ $files = array_merge($files, $params);
+ }
+ foreach ($files as $file) {
+ $command .= ' ' . escapeshellarg($file);
+ }
+ if ($this->config->get('verbose') > 1) {
+ $this->output .= "+ $command\n";
+ }
+ $this->output .= "+ $command\n";
+ if (empty($options['dry-run'])) {
+ $fp = popen($command, "r");
+ while ($line = fgets($fp, 1024)) {
+ $this->output .= rtrim($line)."\n";
+ }
+ pclose($fp);
+ }
+ $this->ui->outputData($this->output, $_cmd);
+ return true;
+ }
+
+ // }}}
+ // {{{ doCvsDiff()
+
+ function doCvsDiff($command, $options, $params)
+ {
+ $this->output = '';
+ if (sizeof($params) < 1) {
+ $help = $this->getHelp($command);
+ return $this->raiseError("$command: missing parameter: $help[0]");
+ }
+ $obj = &$this->getPackageFile($this->config, $this->_debug);
+ $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+ $err = $warn = array();
+ if (!$info->validate()) {
+ foreach ($info->getValidationWarnings() as $error) {
+ if ($error['level'] == 'warning') {
+ $warn[] = $error['message'];
+ } else {
+ $err[] = $error['message'];
+ }
+ }
+ }
+ if (!$this->_displayValidationResults($err, $warn, true)) {
+ $this->ui->outputData($this->output, $command);
+ return $this->raiseError('CVS diff failed');
+ }
+ $info1 = $info->getFilelist();
+ $files = $info1;
+ $cmd = "cvs";
+ if (isset($options['quiet'])) {
+ $cmd .= ' -q';
+ unset($options['quiet']);
+ }
+ if (isset($options['reallyquiet'])) {
+ $cmd .= ' -Q';
+ unset($options['reallyquiet']);
+ }
+ if (isset($options['release'])) {
+ $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']);
+ $cvstag = "RELEASE_$cvsversion";
+ $options['revision'] = $cvstag;
+ unset($options['release']);
+ }
+ $execute = true;
+ if (isset($options['dry-run'])) {
+ $execute = false;
+ unset($options['dry-run']);
+ }
+ $cmd .= ' diff';
+ // the rest of the options are passed right on to "cvs diff"
+ foreach ($options as $option => $optarg) {
+ $arg = $short = false;
+ if (isset($this->commands[$command]['options'][$option])) {
+ $arg = $this->commands[$command]['options'][$option]['arg'];
+ $short = $this->commands[$command]['options'][$option]['shortopt'];
+ }
+ $cmd .= $short ? " -$short" : " --$option";
+ if ($arg && $optarg) {
+ $cmd .= ($short ? '' : '=') . escapeshellarg($optarg);
+ }
+ }
+ foreach ($files as $file) {
+ $cmd .= ' ' . escapeshellarg($file['name']);
+ }
+ if ($this->config->get('verbose') > 1) {
+ $this->output .= "+ $cmd\n";
+ }
+ if ($execute) {
+ $fp = popen($cmd, "r");
+ while ($line = fgets($fp, 1024)) {
+ $this->output .= rtrim($line)."\n";
+ }
+ pclose($fp);
+ }
+ $this->ui->outputData($this->output, $command);
+ return true;
+ }
+
+ // }}}
+ // {{{ doPackageDependencies()
+
+ function doPackageDependencies($command, $options, $params)
+ {
+ // $params[0] -> the PEAR package to list its information
+ if (sizeof($params) != 1) {
+ return $this->raiseError("bad parameter(s), try \"help $command\"");
+ }
+ $obj = &$this->getPackageFile($this->config, $this->_debug);
+ $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+ $deps = $info->getDeps();
+ if (is_array($deps)) {
+ if ($info->getPackagexmlVersion() == '1.0') {
+ $data = array(
+ 'caption' => 'Dependencies for pear/' . $info->getPackage(),
+ 'border' => true,
+ 'headline' => array("Required?", "Type", "Name", "Relation", "Version"),
+ );
+
+ foreach ($deps as $d) {
+ if (isset($d['optional'])) {
+ if ($d['optional'] == 'yes') {
+ $req = 'No';
+ } else {
+ $req = 'Yes';
+ }
+ } else {
+ $req = 'Yes';
+ }
+ if (isset($this->_deps_rel_trans[$d['rel']])) {
+ $rel = $this->_deps_rel_trans[$d['rel']];
+ } else {
+ $rel = $d['rel'];
+ }
+
+ if (isset($this->_deps_type_trans[$d['type']])) {
+ $type = ucfirst($this->_deps_type_trans[$d['type']]);
+ } else {
+ $type = $d['type'];
+ }
+
+ if (isset($d['name'])) {
+ $name = $d['name'];
+ } else {
+ $name = '';
+ }
+
+ if (isset($d['version'])) {
+ $version = $d['version'];
+ } else {
+ $version = '';
+ }
+
+ $data['data'][] = array($req, $type, $name, $rel, $version);
+ }
+ } else { // package.xml 2.0 dependencies display
+ require_once 'PEAR/Dependency2.php';
+ $deps = $info->getDependencies();
+ $reg = &$this->config->getRegistry();
+ if (is_array($deps)) {
+ $d = new PEAR_Dependency2($this->config, array(), '');
+ $data = array(
+ 'caption' => 'Dependencies for ' . $info->getPackage(),
+ 'border' => true,
+ 'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'),
+ );
+ foreach ($deps as $type => $subd) {
+ $req = ($type == 'required') ? 'Yes' : 'No';
+ if ($type == 'group') {
+ $group = $subd['attribs']['name'];
+ } else {
+ $group = '';
+ }
+ if (!isset($subd[0])) {
+ $subd = array($subd);
+ }
+ foreach ($subd as $groupa) {
+ foreach ($groupa as $deptype => $depinfo) {
+ if ($deptype == 'attribs') {
+ continue;
+ }
+ if ($deptype == 'pearinstaller') {
+ $deptype = 'pear Installer';
+ }
+ if (!isset($depinfo[0])) {
+ $depinfo = array($depinfo);
+ }
+ foreach ($depinfo as $inf) {
+ $name = '';
+ if (isset($inf['channel'])) {
+ $alias = $reg->channelAlias($inf['channel']);
+ if (!$alias) {
+ $alias = '(channel?) ' .$inf['channel'];
+ }
+ $name = $alias . '/';
+ }
+ if (isset($inf['name'])) {
+ $name .= $inf['name'];
+ } elseif (isset($inf['pattern'])) {
+ $name .= $inf['pattern'];
+ } else {
+ $name .= '';
+ }
+ if (isset($inf['uri'])) {
+ $name .= ' [' . $inf['uri'] . ']';
+ }
+ if (isset($inf['conflicts'])) {
+ $ver = 'conflicts';
+ } else {
+ $ver = $d->_getExtraString($inf);
+ }
+ $data['data'][] = array($req, ucfirst($deptype), $name,
+ $ver, $group);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ // Fallback
+ $this->ui->outputData("This package does not have any dependencies.", $command);
+ }
+
+ // }}}
+ // {{{ doSign()
+
+ function doSign($command, $options, $params)
+ {
+ require_once 'System.php';
+ require_once 'Archive/Tar.php';
+ // should move most of this code into PEAR_Packager
+ // so it'll be easy to implement "pear package --sign"
+ if (sizeof($params) != 1) {
+ return $this->raiseError("bad parameter(s), try \"help $command\"");
+ }
+ if (!file_exists($params[0])) {
+ return $this->raiseError("file does not exist: $params[0]");
+ }
+ $obj = $this->getPackageFile($this->config, $this->_debug);
+ $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+ $tar = new Archive_Tar($params[0]);
+ $tmpdir = System::mktemp('-d pearsign');
+ if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) {
+ return $this->raiseError("failed to extract tar file");
+ }
+ if (file_exists("$tmpdir/package.sig")) {
+ return $this->raiseError("package already signed");
+ }
+ $packagexml = 'package.xml';
+ if (file_exists("$tmpdir/package2.xml")) {
+ $packagexml = 'package2.xml';
+ }
+ if (file_exists("$tmpdir/package.sig")) {
+ unlink("$tmpdir/package.sig");
+ }
+ if (!file_exists("$tmpdir/$packagexml")) {
+ return $this->raiseError("Extracted file $tmpdir/$packagexml not found.");
+ }
+ $input = $this->ui->userDialog($command,
+ array('GnuPG Passphrase'),
+ array('password'));
+ if (!isset($input[0])) {
+ //use empty passphrase
+ $input[0] = '';
+ }
+
+ $devnull = (isset($options['verbose'])) ? '' : ' 2>/dev/null';
+ $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w");
+ if (!$gpg) {
+ return $this->raiseError("gpg command failed");
+ }
+ fwrite($gpg, "$input[0]\n");
+ if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) {
+ return $this->raiseError("gpg sign failed");
+ }
+ if (!$tar->addModify("$tmpdir/package.sig", '', $tmpdir)) {
+ return $this->raiseError('failed adding signature to file');
+ }
+
+ $this->ui->outputData("Package signed.", $command);
+ return true;
+ }
+
+ // }}}
+
+ /**
+ * For unit testing purposes
+ */
+ function &getInstaller(&$ui)
+ {
+ if (!class_exists('PEAR_Installer')) {
+ require_once 'PEAR/Installer.php';
+ }
+ $a = &new PEAR_Installer($ui);
+ return $a;
+ }
+
+ /**
+ * For unit testing purposes
+ */
+ function &getCommandPackaging(&$ui, &$config)
+ {
+ if (!class_exists('PEAR_Command_Packaging')) {
+ if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true)) {
+ fclose($fp);
+ include_once 'PEAR/Command/Packaging.php';
+ }
+ }
+
+ if (class_exists('PEAR_Command_Packaging')) {
+ $a = &new PEAR_Command_Packaging($ui, $config);
+ } else {
+ $a = null;
+ }
+ return $a;
+ }
+
+ // {{{ doMakeRPM()
+
+ function doMakeRPM($command, $options, $params)
+ {
+
+ // Check to see if PEAR_Command_Packaging is installed, and
+ // transparently switch to use the "make-rpm-spec" command from it
+ // instead, if it does. Otherwise, continue to use the old version
+ // of "makerpm" supplied with this package (PEAR).
+ $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config);
+ if ($packaging_cmd !== null) {
+ $this->ui->outputData('PEAR_Command_Packaging is installed; using '.
+ 'newer "make-rpm-spec" command instead');
+ return $packaging_cmd->run('make-rpm-spec', $options, $params);
+ } else {
+ $this->ui->outputData('WARNING: "pear makerpm" is no longer available; an '.
+ 'improved version is available via "pear make-rpm-spec", which '.
+ 'is available by installing PEAR_Command_Packaging');
+ }
+ return true;
+ }
+
+ function doConvert($command, $options, $params)
+ {
+ $packagexml = isset($params[0]) ? $params[0] : 'package.xml';
+ $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) .
+ DIRECTORY_SEPARATOR . 'package2.xml';
+ $pkg = &$this->getPackageFile($this->config, $this->_debug);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
+ PEAR::staticPopErrorHandling();
+ if (!PEAR::isError($pf)) {
+ if (is_a($pf, 'PEAR_PackageFile_v2')) {
+ $this->ui->outputData($packagexml . ' is already a package.xml version 2.0');
+ return true;
+ }
+ $gen = &$pf->getDefaultGenerator();
+ $newpf = &$gen->toV2();
+ $newpf->setPackagefile($newpackagexml);
+ $gen = &$newpf->getDefaultGenerator();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL);
+ $saved = $gen->toPackageFile(dirname($newpackagexml), $state,
+ basename($newpackagexml));
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($saved)) {
+ if (is_array($saved->getUserInfo())) {
+ foreach ($saved->getUserInfo() as $warning) {
+ $this->ui->outputData($warning['message']);
+ }
+ }
+ $this->ui->outputData($saved->getMessage());
+ return true;
+ }
+ $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"');
+ return true;
+ } else {
+ if (is_array($pf->getUserInfo())) {
+ foreach ($pf->getUserInfo() as $warning) {
+ $this->ui->outputData($warning['message']);
+ }
+ }
+ return $this->raiseError($pf);
+ }
+ }
+
+ // }}}
+}
+
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Package.xml b/vendor/library/Excel/phpxls/PEAR/Command/Package.xml
new file mode 100644
index 0000000..e3f6a55
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Package.xml
@@ -0,0 +1,194 @@
+
+
+ Build Package
+ doPackage
+ p
+
+
+ Z
+ Do not gzip the package file
+
+
+ n
+ Print the name of the packaged file.
+
+
+ [descfile] [descfile2]
+Creates a PEAR package from its description file (usually called
+package.xml). If a second packagefile is passed in, then
+the packager will check to make sure that one is a package.xml
+version 1.0, and the other is a package.xml version 2.0. The
+package.xml version 1.0 will be saved as "package.xml" in the archive,
+and the other as "package2.xml" in the archive"
+
+
+
+ Validate Package Consistency
+ doPackageValidate
+ pv
+
+
+
+
+
+ Run a "cvs diff" for all files in a package
+ doCvsDiff
+ cd
+
+
+ q
+ Be quiet
+
+
+ Q
+ Be really quiet
+
+
+ D
+ Diff against revision of DATE
+ DATE
+
+
+ R
+ Diff against tag for package release REL
+ REL
+
+
+ r
+ Diff against revision REV
+ REV
+
+
+ c
+ Generate context diff
+
+
+ u
+ Generate unified diff
+
+
+ i
+ Ignore case, consider upper- and lower-case letters equivalent
+
+
+ b
+ Ignore changes in amount of white space
+
+
+ B
+ Ignore changes that insert or delete blank lines
+
+
+ Report only whether the files differ, no details
+
+
+ n
+ Don't do anything, just pretend
+
+
+ <package.xml>
+Compares all the files in a package. Without any options, this
+command will compare the current code with the last checked-in code.
+Using the -r or -R option you may compare the current code with that
+of a specific release.
+
+
+
+ Set CVS Release Tag
+ doCvsTag
+ ct
+
+
+ q
+ Be quiet
+
+
+ Q
+ Be really quiet
+
+
+ F
+ Move (slide) tag if it exists
+
+
+ d
+ Remove tag
+
+
+ n
+ Don't do anything, just pretend
+
+
+ <package.xml>
+Sets a CVS tag on all files in a package. Use this command after you have
+packaged a distribution tarball with the "package" command to tag what
+revisions of what files were in that release. If need to fix something
+after running cvstag once, but before the tarball is released to the public,
+use the "slide" option to move the release tag.
+
+
+
+ Show package dependencies
+ doPackageDependencies
+ pd
+
+
+List all dependencies the package has.
+
+
+ Sign a package distribution file
+ doSign
+ si
+
+ <package-file>
+Signs a package distribution (.tar or .tgz) file with GnuPG.
+
+
+ Builds an RPM spec file from a PEAR package
+ doMakeRPM
+ rpm
+
+
+ t
+ FILE
+ Use FILE as RPM spec file template
+
+
+ p
+ FORMAT
+ Use FORMAT as format string for RPM package name, %s is replaced
+by the PEAR package name, defaults to "PEAR::%s".
+
+
+ <package-file>
+
+Creates an RPM .spec file for wrapping a PEAR package inside an RPM
+package. Intended to be used from the SPECS directory, with the PEAR
+package tarball in the SOURCES directory:
+
+$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
+Wrote RPM spec file PEAR::Net_Geo-1.0.spec
+$ rpm -bb PEAR::Net_Socket-1.0.spec
+...
+Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
+
+
+
+ Convert a package.xml 1.0 to package.xml 2.0 format
+ doConvert
+ c2
+
+
+ f
+ do not beautify the filelist.
+
+
+ [descfile] [descfile2]
+Converts a package.xml in 1.0 format into a package.xml
+in 2.0 format. The new file will be named package2.xml by default,
+and package.xml will be used as the old file by default.
+This is not the most intelligent conversion, and should only be
+used for automated conversion or learning the format.
+
+
+
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Pickle.php b/vendor/library/Excel/phpxls/PEAR/Command/Pickle.php
new file mode 100644
index 0000000..d59396a
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Pickle.php
@@ -0,0 +1,376 @@
+
+ * @copyright 2005-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Pickle.php,v 1.8 2008/01/29 03:21:01 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for login/logout
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 2005-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.1
+ */
+
+class PEAR_Command_Pickle extends PEAR_Command_Common
+{
+ var $commands = array(
+ 'pickle' => array(
+ 'summary' => 'Build PECL Package',
+ 'function' => 'doPackage',
+ 'shortcut' => 'pi',
+ 'options' => array(
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'Do not gzip the package file'
+ ),
+ 'showname' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'Print the name of the packaged file.',
+ ),
+ ),
+ 'doc' => '[descfile]
+Creates a PECL package from its package2.xml file.
+
+An automatic conversion will be made to a package.xml 1.0 and written out to
+disk in the current directory as "package.xml". Note that
+only simple package.xml 2.0 will be converted. package.xml 2.0 with:
+
+ - dependency types other than required/optional PECL package/ext/php/pearinstaller
+ - more than one extsrcrelease or zendextsrcrelease
+ - zendextbinrelease, extbinrelease, phprelease, or bundle release type
+ - dependency groups
+ - ignore tags in release filelist
+ - tasks other than replace
+ - custom roles
+
+will cause pickle to fail, and output an error message. If your package2.xml
+uses any of these features, you are best off using PEAR_PackageFileManager to
+generate both package.xml.
+'
+ ),
+ );
+
+ /**
+ * PEAR_Command_Package constructor.
+ *
+ * @access public
+ */
+ function PEAR_Command_Pickle(&$ui, &$config)
+ {
+ parent::PEAR_Command_Common($ui, $config);
+ }
+
+
+ /**
+ * For unit-testing ease
+ *
+ * @return PEAR_Packager
+ */
+ function &getPackager()
+ {
+ if (!class_exists('PEAR_Packager')) {
+ require_once 'PEAR/Packager.php';
+ }
+ $a = &new PEAR_Packager;
+ return $a;
+ }
+
+ /**
+ * For unit-testing ease
+ *
+ * @param PEAR_Config $config
+ * @param bool $debug
+ * @param string|null $tmpdir
+ * @return PEAR_PackageFile
+ */
+ function &getPackageFile($config, $debug = false, $tmpdir = null)
+ {
+ if (!class_exists('PEAR_Common')) {
+ require_once 'PEAR/Common.php';
+ }
+ if (!class_exists('PEAR_PackageFile')) {
+ require_once 'PEAR/PackageFile.php';
+ }
+ $a = &new PEAR_PackageFile($config, $debug, $tmpdir);
+ $common = new PEAR_Common;
+ $common->ui = $this->ui;
+ $a->setLogger($common);
+ return $a;
+ }
+
+ function doPackage($command, $options, $params)
+ {
+ $this->output = '';
+ $pkginfofile = isset($params[0]) ? $params[0] : 'package2.xml';
+ $packager = &$this->getPackager();
+ if (PEAR::isError($err = $this->_convertPackage($pkginfofile))) {
+ return $err;
+ }
+ $compress = empty($options['nocompress']) ? true : false;
+ $result = $packager->package($pkginfofile, $compress, 'package.xml');
+ if (PEAR::isError($result)) {
+ return $this->raiseError($result);
+ }
+ // Don't want output, only the package file name just created
+ if (isset($options['showname'])) {
+ $this->ui->outputData($result, $command);
+ }
+ return true;
+ }
+
+ function _convertPackage($packagexml)
+ {
+ $pkg = &$this->getPackageFile($this->config);
+ $pf2 = &$pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
+ if (!is_a($pf2, 'PEAR_PackageFile_v2')) {
+ return $this->raiseError('Cannot process "' .
+ $packagexml . '", is not a package.xml 2.0');
+ }
+ require_once 'PEAR/PackageFile/v1.php';
+ $pf = new PEAR_PackageFile_v1;
+ $pf->setConfig($this->config);
+ if ($pf2->getPackageType() != 'extsrc' && $pf2->getPackageType() != 'zendextsrc') {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", is not an extension source package. Using a PEAR_PackageFileManager-based ' .
+ 'script is an option');
+ }
+ if (is_array($pf2->getUsesRole())) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains custom roles. Using a PEAR_PackageFileManager-based script or ' .
+ 'the convert command is an option');
+ }
+ if (is_array($pf2->getUsesTask())) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains custom tasks. Using a PEAR_PackageFileManager-based script or ' .
+ 'the convert command is an option');
+ }
+ $deps = $pf2->getDependencies();
+ if (isset($deps['group'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains dependency groups. Using a PEAR_PackageFileManager-based script ' .
+ 'or the convert command is an option');
+ }
+ if (isset($deps['required']['subpackage']) ||
+ isset($deps['optional']['subpackage'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains subpackage dependencies. Using a PEAR_PackageFileManager-based '.
+ 'script is an option');
+ }
+ if (isset($deps['required']['os'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains os dependencies. Using a PEAR_PackageFileManager-based '.
+ 'script is an option');
+ }
+ if (isset($deps['required']['arch'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains arch dependencies. Using a PEAR_PackageFileManager-based '.
+ 'script is an option');
+ }
+ $pf->setPackage($pf2->getPackage());
+ $pf->setSummary($pf2->getSummary());
+ $pf->setDescription($pf2->getDescription());
+ foreach ($pf2->getMaintainers() as $maintainer) {
+ $pf->addMaintainer($maintainer['role'], $maintainer['handle'],
+ $maintainer['name'], $maintainer['email']);
+ }
+ $pf->setVersion($pf2->getVersion());
+ $pf->setDate($pf2->getDate());
+ $pf->setLicense($pf2->getLicense());
+ $pf->setState($pf2->getState());
+ $pf->setNotes($pf2->getNotes());
+ $pf->addPhpDep($deps['required']['php']['min'], 'ge');
+ if (isset($deps['required']['php']['max'])) {
+ $pf->addPhpDep($deps['required']['php']['max'], 'le');
+ }
+ if (isset($deps['required']['package'])) {
+ if (!isset($deps['required']['package'][0])) {
+ $deps['required']['package'] = array($deps['required']['package']);
+ }
+ foreach ($deps['required']['package'] as $dep) {
+ if (!isset($dep['channel'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+ ' contains uri-based dependency on a package. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option');
+ }
+ if ($dep['channel'] != 'pear.php.net' && $dep['channel'] != 'pecl.php.net') {
+ return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+ ' contains dependency on a non-standard channel package. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option');
+ }
+ if (isset($dep['conflicts'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+ ' contains conflicts dependency. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option');
+ }
+ if (isset($dep['exclude'])) {
+ $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
+ }
+ if (isset($dep['min'])) {
+ $pf->addPackageDep($dep['name'], $dep['min'], 'ge');
+ }
+ if (isset($dep['max'])) {
+ $pf->addPackageDep($dep['name'], $dep['max'], 'le');
+ }
+ }
+ }
+ if (isset($deps['required']['extension'])) {
+ if (!isset($deps['required']['extension'][0])) {
+ $deps['required']['extension'] = array($deps['required']['extension']);
+ }
+ foreach ($deps['required']['extension'] as $dep) {
+ if (isset($dep['conflicts'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+ ' contains conflicts dependency. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option');
+ }
+ if (isset($dep['exclude'])) {
+ $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
+ }
+ if (isset($dep['min'])) {
+ $pf->addExtensionDep($dep['name'], $dep['min'], 'ge');
+ }
+ if (isset($dep['max'])) {
+ $pf->addExtensionDep($dep['name'], $dep['max'], 'le');
+ }
+ }
+ }
+ if (isset($deps['optional']['package'])) {
+ if (!isset($deps['optional']['package'][0])) {
+ $deps['optional']['package'] = array($deps['optional']['package']);
+ }
+ foreach ($deps['optional']['package'] as $dep) {
+ if (!isset($dep['channel'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+ ' contains uri-based dependency on a package. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option');
+ }
+ if ($dep['channel'] != 'pear.php.net' && $dep['channel'] != 'pecl.php.net') {
+ return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+ ' contains dependency on a non-standard channel package. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option');
+ }
+ if (isset($dep['exclude'])) {
+ $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
+ }
+ if (isset($dep['min'])) {
+ $pf->addPackageDep($dep['name'], $dep['min'], 'ge', 'yes');
+ }
+ if (isset($dep['max'])) {
+ $pf->addPackageDep($dep['name'], $dep['max'], 'le', 'yes');
+ }
+ }
+ }
+ if (isset($deps['optional']['extension'])) {
+ if (!isset($deps['optional']['extension'][0])) {
+ $deps['optional']['extension'] = array($deps['optional']['extension']);
+ }
+ foreach ($deps['optional']['extension'] as $dep) {
+ if (isset($dep['exclude'])) {
+ $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
+ }
+ if (isset($dep['min'])) {
+ $pf->addExtensionDep($dep['name'], $dep['min'], 'ge', 'yes');
+ }
+ if (isset($dep['max'])) {
+ $pf->addExtensionDep($dep['name'], $dep['max'], 'le', 'yes');
+ }
+ }
+ }
+ $contents = $pf2->getContents();
+ $release = $pf2->getReleases();
+ if (isset($releases[0])) {
+ return $this->raiseError('Cannot safely process "' . $packagexml . '" contains '
+ . 'multiple extsrcrelease/zendextsrcrelease tags. Using a PEAR_PackageFileManager-based script ' .
+ 'or the convert command is an option');
+ }
+ if ($configoptions = $pf2->getConfigureOptions()) {
+ foreach ($configoptions as $option) {
+ $pf->addConfigureOption($option['name'], $option['prompt'],
+ isset($option['default']) ? $option['default'] : false);
+ }
+ }
+ if (isset($release['filelist']['ignore'])) {
+ return $this->raiseError('Cannot safely process "' . $packagexml . '" contains '
+ . 'ignore tags. Using a PEAR_PackageFileManager-based script or the convert' .
+ ' command is an option');
+ }
+ if (isset($release['filelist']['install']) &&
+ !isset($release['filelist']['install'][0])) {
+ $release['filelist']['install'] = array($release['filelist']['install']);
+ }
+ if (isset($contents['dir']['attribs']['baseinstalldir'])) {
+ $baseinstalldir = $contents['dir']['attribs']['baseinstalldir'];
+ } else {
+ $baseinstalldir = false;
+ }
+ if (!isset($contents['dir']['file'][0])) {
+ $contents['dir']['file'] = array($contents['dir']['file']);
+ }
+ foreach ($contents['dir']['file'] as $file) {
+ if ($baseinstalldir && !isset($file['attribs']['baseinstalldir'])) {
+ $file['attribs']['baseinstalldir'] = $baseinstalldir;
+ }
+ $processFile = $file;
+ unset($processFile['attribs']);
+ if (count($processFile)) {
+ foreach ($processFile as $name => $task) {
+ if ($name != $pf2->getTasksNs() . ':replace') {
+ return $this->raiseError('Cannot safely process "' . $packagexml .
+ '" contains tasks other than replace. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option.');
+ }
+ $file['attribs']['replace'][] = $task;
+ }
+ }
+ if (!in_array($file['attribs']['role'], PEAR_Common::getFileRoles())) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains custom roles. Using a PEAR_PackageFileManager-based script ' .
+ 'or the convert command is an option');
+ }
+ if (isset($release['filelist']['install'])) {
+ foreach ($release['filelist']['install'] as $installas) {
+ if ($installas['attribs']['name'] == $file['attribs']['name']) {
+ $file['attribs']['install-as'] = $installas['attribs']['as'];
+ }
+ }
+ }
+ $pf->addFile('/', $file['attribs']['name'], $file['attribs']);
+ }
+ if ($pf2->getChangeLog()) {
+ $this->ui->outputData('WARNING: changelog is not translated to package.xml ' .
+ '1.0, use PEAR_PackageFileManager-based script if you need changelog-' .
+ 'translation for package.xml 1.0');
+ }
+ $gen = &$pf->getDefaultGenerator();
+ $gen->toPackageFile('.');
+ }
+}
+
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Pickle.xml b/vendor/library/Excel/phpxls/PEAR/Command/Pickle.xml
new file mode 100644
index 0000000..04c85bc
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Pickle.xml
@@ -0,0 +1,40 @@
+
+
+ Build PECL Package
+ doPackage
+ pi
+
+
+ Z
+ Do not gzip the package file
+
+
+ n
+ Print the name of the packaged file.
+
+
+ [descfile] [descfile2]
+Creates a PECL package from its description file (usually called
+package.xml). If a second packagefile is passed in, then
+the packager will check to make sure that one is a package.xml
+version 1.0, and the other is a package.xml version 2.0. The
+package.xml version 1.0 will be saved as "package.xml" in the archive,
+and the other as "package2.xml" in the archive"
+
+If no second file is passed in, and [descfile] is a package.xml 2.0,
+an automatic conversion will be made to a package.xml 1.0. Note that
+only simple package.xml 2.0 will be converted. package.xml 2.0 with:
+
+ - dependency types other than required/optional PECL package/ext/php/pearinstaller
+ - more than one extsrcrelease/zendextsrcrelease
+ - zendextbinrelease, extbinrelease, phprelease, or bundle release type
+ - dependency groups
+ - ignore tags in release filelist
+ - tasks other than replace
+ - custom roles
+
+will cause pickle to fail, and output an error message. If your package2.xml
+uses any of these features, you are best off using PEAR_PackageFileManager to
+generate both package.xml.
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Registry.php b/vendor/library/Excel/phpxls/PEAR/Command/Registry.php
new file mode 100644
index 0000000..d2f1dd1
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Registry.php
@@ -0,0 +1,1070 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Registry.php,v 1.81 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for registry manipulation
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Registry extends PEAR_Command_Common
+{
+ // {{{ properties
+
+ var $commands = array(
+ 'list' => array(
+ 'summary' => 'List Installed Packages In The Default Channel',
+ 'function' => 'doList',
+ 'shortcut' => 'l',
+ 'options' => array(
+ 'channel' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'list installed packages from this channel',
+ 'arg' => 'CHAN',
+ ),
+ 'allchannels' => array(
+ 'shortopt' => 'a',
+ 'doc' => 'list installed packages from all channels',
+ ),
+ 'channelinfo' => array(
+ 'shortopt' => 'i',
+ 'doc' => 'output fully channel-aware data, even on failure',
+ ),
+ ),
+ 'doc' => '
+If invoked without parameters, this command lists the PEAR packages
+installed in your php_dir ({config php_dir}). With a parameter, it
+lists the files in a package.
+',
+ ),
+ 'list-files' => array(
+ 'summary' => 'List Files In Installed Package',
+ 'function' => 'doFileList',
+ 'shortcut' => 'fl',
+ 'options' => array(),
+ 'doc' => '
+List the files in an installed package.
+'
+ ),
+ 'shell-test' => array(
+ 'summary' => 'Shell Script Test',
+ 'function' => 'doShellTest',
+ 'shortcut' => 'st',
+ 'options' => array(),
+ 'doc' => ' [[relation] version]
+Tests if a package is installed in the system. Will exit(1) if it is not.
+ The version comparison operator. One of:
+ <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne
+ The version to compare with
+'),
+ 'info' => array(
+ 'summary' => 'Display information about a package',
+ 'function' => 'doInfo',
+ 'shortcut' => 'in',
+ 'options' => array(),
+ 'doc' => '
+Displays information about a package. The package argument may be a
+local package file, an URL to a package file, or the name of an
+installed package.'
+ )
+ );
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * PEAR_Command_Registry constructor.
+ *
+ * @access public
+ */
+ function PEAR_Command_Registry(&$ui, &$config)
+ {
+ parent::PEAR_Command_Common($ui, $config);
+ }
+
+ // }}}
+
+ // {{{ doList()
+
+ function _sortinfo($a, $b)
+ {
+ $apackage = isset($a['package']) ? $a['package'] : $a['name'];
+ $bpackage = isset($b['package']) ? $b['package'] : $b['name'];
+ return strcmp($apackage, $bpackage);
+ }
+
+ function doList($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+ $channelinfo = isset($options['channelinfo']);
+ if (isset($options['allchannels']) && !$channelinfo) {
+ return $this->doListAll($command, array(), $params);
+ }
+ if (isset($options['allchannels']) && $channelinfo) {
+ // allchannels with $channelinfo
+ unset($options['allchannels']);
+ $channels = $reg->getChannels();
+ $errors = array();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ foreach ($channels as $channel) {
+ $options['channel'] = $channel->getName();
+ $ret = $this->doList($command, $options, $params);
+
+ if (PEAR::isError($ret)) {
+ $errors[] = $ret;
+ }
+ }
+ PEAR::staticPopErrorHandling();
+ if (count($errors)) {
+ // for now, only give first error
+ return PEAR::raiseError($errors[0]);
+ }
+ return true;
+ }
+
+ if (count($params) == 1) {
+ return $this->doFileList($command, $options, $params);
+ }
+ if (isset($options['channel'])) {
+ if ($reg->channelExists($options['channel'])) {
+ $channel = $reg->channelName($options['channel']);
+ } else {
+ return $this->raiseError('Channel "' . $options['channel'] .'" does not exist');
+ }
+ } else {
+ $channel = $this->config->get('default_channel');
+ }
+ $installed = $reg->packageInfo(null, null, $channel);
+ usort($installed, array(&$this, '_sortinfo'));
+
+ $data = array(
+ 'caption' => 'Installed packages, channel ' .
+ $channel . ':',
+ 'border' => true,
+ 'headline' => array('Package', 'Version', 'State'),
+ 'channel' => $channel,
+ );
+ if ($channelinfo) {
+ $data['headline'] = array('Channel', 'Package', 'Version', 'State');
+ }
+
+ if (count($installed) && !isset($data['data'])) {
+ $data['data'] = array();
+ }
+
+ foreach ($installed as $package) {
+ $pobj = $reg->getPackage(isset($package['package']) ?
+ $package['package'] : $package['name'], $channel);
+ if ($channelinfo) {
+ $packageinfo = array($pobj->getChannel(), $pobj->getPackage(), $pobj->getVersion(),
+ $pobj->getState() ? $pobj->getState() : null);
+ } else {
+ $packageinfo = array($pobj->getPackage(), $pobj->getVersion(),
+ $pobj->getState() ? $pobj->getState() : null);
+ }
+ $data['data'][] = $packageinfo;
+ }
+ if (count($installed) == 0) {
+ if (!$channelinfo) {
+ $data = '(no packages installed from channel ' . $channel . ')';
+ } else {
+ $data = array(
+ 'caption' => 'Installed packages, channel ' .
+ $channel . ':',
+ 'border' => true,
+ 'channel' => $channel,
+ 'data' => '(no packages installed)',
+ );
+ }
+ }
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ function doListAll($command, $options, $params)
+ {
+ // This duplicate code is deprecated over
+ // list --channelinfo, which gives identical
+ // output for list and list --allchannels.
+ $reg = &$this->config->getRegistry();
+ $installed = $reg->packageInfo(null, null, null);
+ foreach ($installed as $channel => $packages) {
+ usort($packages, array($this, '_sortinfo'));
+ $data = array(
+ 'caption' => 'Installed packages, channel ' . $channel . ':',
+ 'border' => true,
+ 'headline' => array('Package', 'Version', 'State'),
+ 'channel' => $channel
+ );
+ foreach ($packages as $package) {
+ $pobj = $reg->getPackage(isset($package['package']) ?
+ $package['package'] : $package['name'], $channel);
+ $data['data'][] = array($pobj->getPackage(), $pobj->getVersion(),
+ $pobj->getState() ? $pobj->getState() : null);
+ }
+ if (count($packages)==0) {
+ $data = array(
+ 'caption' => 'Installed packages, channel ' . $channel . ':',
+ 'border' => true,
+ 'data' => array(array('(no packages installed)')),
+ 'channel' => $channel
+ );
+ }
+ $this->ui->outputData($data, $command);
+ }
+ return true;
+ }
+
+ function doFileList($command, $options, $params)
+ {
+ if (count($params) != 1) {
+ return $this->raiseError('list-files expects 1 parameter');
+ }
+ $reg = &$this->config->getRegistry();
+ $fp = false;
+ if (!is_dir($params[0]) && (file_exists($params[0]) || $fp = @fopen($params[0],
+ 'r'))) {
+ if ($fp) {
+ fclose($fp);
+ }
+ if (!class_exists('PEAR_PackageFile')) {
+ require_once 'PEAR/PackageFile.php';
+ }
+ $pkg = &new PEAR_PackageFile($this->config, $this->_debug);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $info = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
+ PEAR::staticPopErrorHandling();
+ $headings = array('Package File', 'Install Path');
+ $installed = false;
+ } else {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($parsed)) {
+ return $this->raiseError($parsed);
+ }
+ $info = &$reg->getPackage($parsed['package'], $parsed['channel']);
+ $headings = array('Type', 'Install Path');
+ $installed = true;
+ }
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+ if ($info === null) {
+ return $this->raiseError("`$params[0]' not installed");
+ }
+ $list = ($info->getPackagexmlVersion() == '1.0' || $installed) ?
+ $info->getFilelist() : $info->getContents();
+ if ($installed) {
+ $caption = 'Installed Files For ' . $params[0];
+ } else {
+ $caption = 'Contents of ' . basename($params[0]);
+ }
+ $data = array(
+ 'caption' => $caption,
+ 'border' => true,
+ 'headline' => $headings);
+ if ($info->getPackagexmlVersion() == '1.0' || $installed) {
+ foreach ($list as $file => $att) {
+ if ($installed) {
+ if (empty($att['installed_as'])) {
+ continue;
+ }
+ $data['data'][] = array($att['role'], $att['installed_as']);
+ } else {
+ if (isset($att['baseinstalldir']) && !in_array($att['role'],
+ array('test', 'data', 'doc'))) {
+ $dest = $att['baseinstalldir'] . DIRECTORY_SEPARATOR .
+ $file;
+ } else {
+ $dest = $file;
+ }
+ switch ($att['role']) {
+ case 'test':
+ case 'data':
+ case 'doc':
+ $role = $att['role'];
+ if ($role == 'test') {
+ $role .= 's';
+ }
+ $dest = $this->config->get($role . '_dir') . DIRECTORY_SEPARATOR .
+ $info->getPackage() . DIRECTORY_SEPARATOR . $dest;
+ break;
+ case 'php':
+ default:
+ $dest = $this->config->get('php_dir') . DIRECTORY_SEPARATOR .
+ $dest;
+ }
+ $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
+ $dest = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
+ array(DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR),
+ $dest);
+ $file = preg_replace('!/+!', '/', $file);
+ $data['data'][] = array($file, $dest);
+ }
+ }
+ } else { // package.xml 2.0, not installed
+ if (!isset($list['dir']['file'][0])) {
+ $list['dir']['file'] = array($list['dir']['file']);
+ }
+ foreach ($list['dir']['file'] as $att) {
+ $att = $att['attribs'];
+ $file = $att['name'];
+ $role = &PEAR_Installer_Role::factory($info, $att['role'], $this->config);
+ $role->setup($this, $info, $att, $file);
+ if (!$role->isInstallable()) {
+ $dest = '(not installable)';
+ } else {
+ $dest = $role->processInstallation($info, $att, $file, '');
+ if (PEAR::isError($dest)) {
+ $dest = '(Unknown role "' . $att['role'] . ')';
+ } else {
+ list(,, $dest) = $dest;
+ }
+ }
+ $data['data'][] = array($file, $dest);
+ }
+ }
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ // }}}
+ // {{{ doShellTest()
+
+ function doShellTest($command, $options, $params)
+ {
+ if (count($params) < 1) {
+ return PEAR::raiseError('ERROR, usage: pear shell-test packagename [[relation] version]');
+ }
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $reg = &$this->config->getRegistry();
+ $info = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
+ if (PEAR::isError($info)) {
+ exit(1); // invalid package name
+ }
+ $package = $info['package'];
+ $channel = $info['channel'];
+ // "pear shell-test Foo"
+ if (!$reg->packageExists($package, $channel)) {
+ if ($channel == 'pecl.php.net') {
+ if ($reg->packageExists($package, 'pear.php.net')) {
+ $channel = 'pear.php.net'; // magically change channels for extensions
+ }
+ }
+ }
+ if (sizeof($params) == 1) {
+ if (!$reg->packageExists($package, $channel)) {
+ exit(1);
+ }
+ // "pear shell-test Foo 1.0"
+ } elseif (sizeof($params) == 2) {
+ $v = $reg->packageInfo($package, 'version', $channel);
+ if (!$v || !version_compare("$v", "{$params[1]}", "ge")) {
+ exit(1);
+ }
+ // "pear shell-test Foo ge 1.0"
+ } elseif (sizeof($params) == 3) {
+ $v = $reg->packageInfo($package, 'version', $channel);
+ if (!$v || !version_compare("$v", "{$params[2]}", $params[1])) {
+ exit(1);
+ }
+ } else {
+ PEAR::staticPopErrorHandling();
+ $this->raiseError("$command: expects 1 to 3 parameters");
+ exit(1);
+ }
+ }
+
+ // }}}
+ // {{{ doInfo
+
+ function doInfo($command, $options, $params)
+ {
+ if (count($params) != 1) {
+ return $this->raiseError('pear info expects 1 parameter');
+ }
+ $info = $fp = false;
+ $reg = &$this->config->getRegistry();
+ if ((file_exists($params[0]) && is_file($params[0]) && !is_dir($params[0])) || $fp = @fopen($params[0], 'r')) {
+ if ($fp) {
+ fclose($fp);
+ }
+ if (!class_exists('PEAR_PackageFile')) {
+ require_once 'PEAR/PackageFile.php';
+ }
+ $pkg = &new PEAR_PackageFile($this->config, $this->_debug);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $obj = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($obj)) {
+ $uinfo = $obj->getUserInfo();
+ if (is_array($uinfo)) {
+ foreach ($uinfo as $message) {
+ if (is_array($message)) {
+ $message = $message['message'];
+ }
+ $this->ui->outputData($message);
+ }
+ }
+ return $this->raiseError($obj);
+ }
+ if ($obj->getPackagexmlVersion() == '1.0') {
+ $info = $obj->toArray();
+ } else {
+ return $this->_doInfo2($command, $options, $params, $obj, false);
+ }
+ } else {
+ $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
+ if (PEAR::isError($parsed)) {
+ return $this->raiseError($parsed);
+ }
+ $package = $parsed['package'];
+ $channel = $parsed['channel'];
+ $info = $reg->packageInfo($package, null, $channel);
+ if (isset($info['old'])) {
+ $obj = $reg->getPackage($package, $channel);
+ return $this->_doInfo2($command, $options, $params, $obj, true);
+ }
+ }
+ if (PEAR::isError($info)) {
+ return $info;
+ }
+ if (empty($info)) {
+ $this->raiseError("No information found for `$params[0]'");
+ return;
+ }
+ unset($info['filelist']);
+ unset($info['dirtree']);
+ unset($info['changelog']);
+ if (isset($info['xsdversion'])) {
+ $info['package.xml version'] = $info['xsdversion'];
+ unset($info['xsdversion']);
+ }
+ if (isset($info['packagerversion'])) {
+ $info['packaged with PEAR version'] = $info['packagerversion'];
+ unset($info['packagerversion']);
+ }
+ $keys = array_keys($info);
+ $longtext = array('description', 'summary');
+ foreach ($keys as $key) {
+ if (is_array($info[$key])) {
+ switch ($key) {
+ case 'maintainers': {
+ $i = 0;
+ $mstr = '';
+ foreach ($info[$key] as $m) {
+ if ($i++ > 0) {
+ $mstr .= "\n";
+ }
+ $mstr .= $m['name'] . " <";
+ if (isset($m['email'])) {
+ $mstr .= $m['email'];
+ } else {
+ $mstr .= $m['handle'] . '@php.net';
+ }
+ $mstr .= "> ($m[role])";
+ }
+ $info[$key] = $mstr;
+ break;
+ }
+ case 'release_deps': {
+ $i = 0;
+ $dstr = '';
+ foreach ($info[$key] as $d) {
+ if (isset($this->_deps_rel_trans[$d['rel']])) {
+ $rel = $this->_deps_rel_trans[$d['rel']];
+ } else {
+ $rel = $d['rel'];
+ }
+ if (isset($this->_deps_type_trans[$d['type']])) {
+ $type = ucfirst($this->_deps_type_trans[$d['type']]);
+ } else {
+ $type = $d['type'];
+ }
+ if (isset($d['name'])) {
+ $name = $d['name'] . ' ';
+ } else {
+ $name = '';
+ }
+ if (isset($d['version'])) {
+ $version = $d['version'] . ' ';
+ } else {
+ $version = '';
+ }
+ if (isset($d['optional']) && $d['optional'] == 'yes') {
+ $optional = ' (optional)';
+ } else {
+ $optional = '';
+ }
+ $dstr .= "$type $name$rel $version$optional\n";
+ }
+ $info[$key] = $dstr;
+ break;
+ }
+ case 'provides' : {
+ $debug = $this->config->get('verbose');
+ if ($debug < 2) {
+ $pstr = 'Classes: ';
+ } else {
+ $pstr = '';
+ }
+ $i = 0;
+ foreach ($info[$key] as $p) {
+ if ($debug < 2 && $p['type'] != "class") {
+ continue;
+ }
+ // Only print classes when verbosity mode is < 2
+ if ($debug < 2) {
+ if ($i++ > 0) {
+ $pstr .= ", ";
+ }
+ $pstr .= $p['name'];
+ } else {
+ if ($i++ > 0) {
+ $pstr .= "\n";
+ }
+ $pstr .= ucfirst($p['type']) . " " . $p['name'];
+ if (isset($p['explicit']) && $p['explicit'] == 1) {
+ $pstr .= " (explicit)";
+ }
+ }
+ }
+ $info[$key] = $pstr;
+ break;
+ }
+ case 'configure_options' : {
+ foreach ($info[$key] as $i => $p) {
+ $info[$key][$i] = array_map(null, array_keys($p), array_values($p));
+ $info[$key][$i] = array_map(create_function('$a',
+ 'return join(" = ",$a);'), $info[$key][$i]);
+ $info[$key][$i] = implode(', ', $info[$key][$i]);
+ }
+ $info[$key] = implode("\n", $info[$key]);
+ break;
+ }
+ default: {
+ $info[$key] = implode(", ", $info[$key]);
+ break;
+ }
+ }
+ }
+ if ($key == '_lastmodified') {
+ $hdate = date('Y-m-d', $info[$key]);
+ unset($info[$key]);
+ $info['Last Modified'] = $hdate;
+ } elseif ($key == '_lastversion') {
+ $info['Previous Installed Version'] = $info[$key] ? $info[$key] : '- None -';
+ unset($info[$key]);
+ } else {
+ $info[$key] = trim($info[$key]);
+ if (in_array($key, $longtext)) {
+ $info[$key] = preg_replace('/ +/', ' ', $info[$key]);
+ }
+ }
+ }
+ $caption = 'About ' . $info['package'] . '-' . $info['version'];
+ $data = array(
+ 'caption' => $caption,
+ 'border' => true);
+ foreach ($info as $key => $value) {
+ $key = ucwords(trim(str_replace('_', ' ', $key)));
+ $data['data'][] = array($key, $value);
+ }
+ $data['raw'] = $info;
+
+ $this->ui->outputData($data, 'package-info');
+ }
+
+ // }}}
+
+ /**
+ * @access private
+ */
+ function _doInfo2($command, $options, $params, &$obj, $installed)
+ {
+ $reg = &$this->config->getRegistry();
+ $caption = 'About ' . $obj->getChannel() . '/' .$obj->getPackage() . '-' .
+ $obj->getVersion();
+ $data = array(
+ 'caption' => $caption,
+ 'border' => true);
+ switch ($obj->getPackageType()) {
+ case 'php' :
+ $release = 'PEAR-style PHP-based Package';
+ break;
+ case 'extsrc' :
+ $release = 'PECL-style PHP extension (source code)';
+ break;
+ case 'zendextsrc' :
+ $release = 'PECL-style Zend extension (source code)';
+ break;
+ case 'extbin' :
+ $release = 'PECL-style PHP extension (binary)';
+ break;
+ case 'zendextbin' :
+ $release = 'PECL-style Zend extension (binary)';
+ break;
+ case 'bundle' :
+ $release = 'Package bundle (collection of packages)';
+ break;
+ }
+ $extends = $obj->getExtends();
+ $extends = $extends ?
+ $obj->getPackage() . ' (extends ' . $extends . ')' : $obj->getPackage();
+ if ($src = $obj->getSourcePackage()) {
+ $extends .= ' (source package ' . $src['channel'] . '/' . $src['package'] . ')';
+ }
+ $info = array(
+ 'Release Type' => $release,
+ 'Name' => $extends,
+ 'Channel' => $obj->getChannel(),
+ 'Summary' => preg_replace('/ +/', ' ', $obj->getSummary()),
+ 'Description' => preg_replace('/ +/', ' ', $obj->getDescription()),
+ );
+ $info['Maintainers'] = '';
+ foreach (array('lead', 'developer', 'contributor', 'helper') as $role) {
+ $leads = $obj->{"get{$role}s"}();
+ if (!$leads) {
+ continue;
+ }
+ if (isset($leads['active'])) {
+ $leads = array($leads);
+ }
+ foreach ($leads as $lead) {
+ if (!empty($info['Maintainers'])) {
+ $info['Maintainers'] .= "\n";
+ }
+ $info['Maintainers'] .= $lead['name'] . ' <';
+ $info['Maintainers'] .= $lead['email'] . "> ($role)";
+ }
+ }
+ $info['Release Date'] = $obj->getDate();
+ if ($time = $obj->getTime()) {
+ $info['Release Date'] .= ' ' . $time;
+ }
+ $info['Release Version'] = $obj->getVersion() . ' (' . $obj->getState() . ')';
+ $info['API Version'] = $obj->getVersion('api') . ' (' . $obj->getState('api') . ')';
+ $info['License'] = $obj->getLicense();
+ $uri = $obj->getLicenseLocation();
+ if ($uri) {
+ if (isset($uri['uri'])) {
+ $info['License'] .= ' (' . $uri['uri'] . ')';
+ } else {
+ $extra = $obj->getInstalledLocation($info['filesource']);
+ if ($extra) {
+ $info['License'] .= ' (' . $uri['filesource'] . ')';
+ }
+ }
+ }
+ $info['Release Notes'] = $obj->getNotes();
+ if ($compat = $obj->getCompatible()) {
+ if (!isset($compat[0])) {
+ $compat = array($compat);
+ }
+ $info['Compatible with'] = '';
+ foreach ($compat as $package) {
+ $info['Compatible with'] .= $package['channel'] . '/' . $package['name'] .
+ "\nVersions >= " . $package['min'] . ', <= ' . $package['max'];
+ if (isset($package['exclude'])) {
+ if (is_array($package['exclude'])) {
+ $package['exclude'] = implode(', ', $package['exclude']);
+ }
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ $info['Not Compatible with'] .= $package['channel'] . '/' .
+ $package['name'] . "\nVersions " . $package['exclude'];
+ }
+ }
+ }
+ $usesrole = $obj->getUsesrole();
+ if ($usesrole) {
+ if (!isset($usesrole[0])) {
+ $usesrole = array($usesrole);
+ }
+ foreach ($usesrole as $roledata) {
+ if (isset($info['Uses Custom Roles'])) {
+ $info['Uses Custom Roles'] .= "\n";
+ } else {
+ $info['Uses Custom Roles'] = '';
+ }
+ if (isset($roledata['package'])) {
+ $rolepackage = $reg->parsedPackageNameToString($roledata, true);
+ } else {
+ $rolepackage = $roledata['uri'];
+ }
+ $info['Uses Custom Roles'] .= $roledata['role'] . ' (' . $rolepackage . ')';
+ }
+ }
+ $usestask = $obj->getUsestask();
+ if ($usestask) {
+ if (!isset($usestask[0])) {
+ $usestask = array($usestask);
+ }
+ foreach ($usestask as $taskdata) {
+ if (isset($info['Uses Custom Tasks'])) {
+ $info['Uses Custom Tasks'] .= "\n";
+ } else {
+ $info['Uses Custom Tasks'] = '';
+ }
+ if (isset($taskdata['package'])) {
+ $taskpackage = $reg->parsedPackageNameToString($taskdata, true);
+ } else {
+ $taskpackage = $taskdata['uri'];
+ }
+ $info['Uses Custom Tasks'] .= $taskdata['task'] . ' (' . $taskpackage . ')';
+ }
+ }
+ $deps = $obj->getDependencies();
+ $info['Required Dependencies'] = 'PHP version ' . $deps['required']['php']['min'];
+ if (isset($deps['required']['php']['max'])) {
+ $info['Required Dependencies'] .= '-' . $deps['required']['php']['max'] . "\n";
+ } else {
+ $info['Required Dependencies'] .= "\n";
+ }
+ if (isset($deps['required']['php']['exclude'])) {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ if (is_array($deps['required']['php']['exclude'])) {
+ $deps['required']['php']['exclude'] =
+ implode(', ', $deps['required']['php']['exclude']);
+ }
+ $info['Not Compatible with'] .= "PHP versions\n " .
+ $deps['required']['php']['exclude'];
+ }
+ $info['Required Dependencies'] .= 'PEAR installer version';
+ if (isset($deps['required']['pearinstaller']['max'])) {
+ $info['Required Dependencies'] .= 's ' .
+ $deps['required']['pearinstaller']['min'] . '-' .
+ $deps['required']['pearinstaller']['max'];
+ } else {
+ $info['Required Dependencies'] .= ' ' .
+ $deps['required']['pearinstaller']['min'] . ' or newer';
+ }
+ if (isset($deps['required']['pearinstaller']['exclude'])) {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ if (is_array($deps['required']['pearinstaller']['exclude'])) {
+ $deps['required']['pearinstaller']['exclude'] =
+ implode(', ', $deps['required']['pearinstaller']['exclude']);
+ }
+ $info['Not Compatible with'] .= "PEAR installer\n Versions " .
+ $deps['required']['pearinstaller']['exclude'];
+ }
+ foreach (array('Package', 'Extension') as $type) {
+ $index = strtolower($type);
+ if (isset($deps['required'][$index])) {
+ if (isset($deps['required'][$index]['name'])) {
+ $deps['required'][$index] = array($deps['required'][$index]);
+ }
+ foreach ($deps['required'][$index] as $package) {
+ if (isset($package['conflicts'])) {
+ $infoindex = 'Not Compatible with';
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ } else {
+ $infoindex = 'Required Dependencies';
+ $info[$infoindex] .= "\n";
+ }
+ if ($index == 'extension') {
+ $name = $package['name'];
+ } else {
+ if (isset($package['channel'])) {
+ $name = $package['channel'] . '/' . $package['name'];
+ } else {
+ $name = '__uri/' . $package['name'] . ' (static URI)';
+ }
+ }
+ $info[$infoindex] .= "$type $name";
+ if (isset($package['uri'])) {
+ $info[$infoindex] .= "\n Download URI: $package[uri]";
+ continue;
+ }
+ if (isset($package['max']) && isset($package['min'])) {
+ $info[$infoindex] .= " \n Versions " .
+ $package['min'] . '-' . $package['max'];
+ } elseif (isset($package['min'])) {
+ $info[$infoindex] .= " \n Version " .
+ $package['min'] . ' or newer';
+ } elseif (isset($package['max'])) {
+ $info[$infoindex] .= " \n Version " .
+ $package['max'] . ' or older';
+ }
+ if (isset($package['recommended'])) {
+ $info[$infoindex] .= "\n Recommended version: $package[recommended]";
+ }
+ if (isset($package['exclude'])) {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ if (is_array($package['exclude'])) {
+ $package['exclude'] = implode(', ', $package['exclude']);
+ }
+ $package['package'] = $package['name']; // for parsedPackageNameToString
+ if (isset($package['conflicts'])) {
+ $info['Not Compatible with'] .= '=> except ';
+ }
+ $info['Not Compatible with'] .= 'Package ' .
+ $reg->parsedPackageNameToString($package, true);
+ $info['Not Compatible with'] .= "\n Versions " . $package['exclude'];
+ }
+ }
+ }
+ }
+ if (isset($deps['required']['os'])) {
+ if (isset($deps['required']['os']['name'])) {
+ $dep['required']['os']['name'] = array($dep['required']['os']['name']);
+ }
+ foreach ($dep['required']['os'] as $os) {
+ if (isset($os['conflicts']) && $os['conflicts'] == 'yes') {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ $info['Not Compatible with'] .= "$os[name] Operating System";
+ } else {
+ $info['Required Dependencies'] .= "\n";
+ $info['Required Dependencies'] .= "$os[name] Operating System";
+ }
+ }
+ }
+ if (isset($deps['required']['arch'])) {
+ if (isset($deps['required']['arch']['pattern'])) {
+ $dep['required']['arch']['pattern'] = array($dep['required']['os']['pattern']);
+ }
+ foreach ($dep['required']['arch'] as $os) {
+ if (isset($os['conflicts']) && $os['conflicts'] == 'yes') {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ $info['Not Compatible with'] .= "OS/Arch matching pattern '/$os[pattern]/'";
+ } else {
+ $info['Required Dependencies'] .= "\n";
+ $info['Required Dependencies'] .= "OS/Arch matching pattern '/$os[pattern]/'";
+ }
+ }
+ }
+ if (isset($deps['optional'])) {
+ foreach (array('Package', 'Extension') as $type) {
+ $index = strtolower($type);
+ if (isset($deps['optional'][$index])) {
+ if (isset($deps['optional'][$index]['name'])) {
+ $deps['optional'][$index] = array($deps['optional'][$index]);
+ }
+ foreach ($deps['optional'][$index] as $package) {
+ if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
+ $infoindex = 'Not Compatible with';
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ } else {
+ $infoindex = 'Optional Dependencies';
+ if (!isset($info['Optional Dependencies'])) {
+ $info['Optional Dependencies'] = '';
+ } else {
+ $info['Optional Dependencies'] .= "\n";
+ }
+ }
+ if ($index == 'extension') {
+ $name = $package['name'];
+ } else {
+ if (isset($package['channel'])) {
+ $name = $package['channel'] . '/' . $package['name'];
+ } else {
+ $name = '__uri/' . $package['name'] . ' (static URI)';
+ }
+ }
+ $info[$infoindex] .= "$type $name";
+ if (isset($package['uri'])) {
+ $info[$infoindex] .= "\n Download URI: $package[uri]";
+ continue;
+ }
+ if ($infoindex == 'Not Compatible with') {
+ // conflicts is only used to say that all versions conflict
+ continue;
+ }
+ if (isset($package['max']) && isset($package['min'])) {
+ $info[$infoindex] .= " \n Versions " .
+ $package['min'] . '-' . $package['max'];
+ } elseif (isset($package['min'])) {
+ $info[$infoindex] .= " \n Version " .
+ $package['min'] . ' or newer';
+ } elseif (isset($package['max'])) {
+ $info[$infoindex] .= " \n Version " .
+ $package['min'] . ' or older';
+ }
+ if (isset($package['recommended'])) {
+ $info[$infoindex] .= "\n Recommended version: $package[recommended]";
+ }
+ if (isset($package['exclude'])) {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ if (is_array($package['exclude'])) {
+ $package['exclude'] = implode(', ', $package['exclude']);
+ }
+ $info['Not Compatible with'] .= "Package $package\n Versions " .
+ $package['exclude'];
+ }
+ }
+ }
+ }
+ }
+ if (isset($deps['group'])) {
+ if (!isset($deps['group'][0])) {
+ $deps['group'] = array($deps['group']);
+ }
+ foreach ($deps['group'] as $group) {
+ $info['Dependency Group ' . $group['attribs']['name']] = $group['attribs']['hint'];
+ $groupindex = $group['attribs']['name'] . ' Contents';
+ $info[$groupindex] = '';
+ foreach (array('Package', 'Extension') as $type) {
+ $index = strtolower($type);
+ if (isset($group[$index])) {
+ if (isset($group[$index]['name'])) {
+ $group[$index] = array($group[$index]);
+ }
+ foreach ($group[$index] as $package) {
+ if (!empty($info[$groupindex])) {
+ $info[$groupindex] .= "\n";
+ }
+ if ($index == 'extension') {
+ $name = $package['name'];
+ } else {
+ if (isset($package['channel'])) {
+ $name = $package['channel'] . '/' . $package['name'];
+ } else {
+ $name = '__uri/' . $package['name'] . ' (static URI)';
+ }
+ }
+ if (isset($package['uri'])) {
+ if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
+ $info[$groupindex] .= "Not Compatible with $type $name";
+ } else {
+ $info[$groupindex] .= "$type $name";
+ }
+ $info[$groupindex] .= "\n Download URI: $package[uri]";
+ continue;
+ }
+ if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
+ $info[$groupindex] .= "Not Compatible with $type $name";
+ continue;
+ }
+ $info[$groupindex] .= "$type $name";
+ if (isset($package['max']) && isset($package['min'])) {
+ $info[$groupindex] .= " \n Versions " .
+ $package['min'] . '-' . $package['max'];
+ } elseif (isset($package['min'])) {
+ $info[$groupindex] .= " \n Version " .
+ $package['min'] . ' or newer';
+ } elseif (isset($package['max'])) {
+ $info[$groupindex] .= " \n Version " .
+ $package['min'] . ' or older';
+ }
+ if (isset($package['recommended'])) {
+ $info[$groupindex] .= "\n Recommended version: $package[recommended]";
+ }
+ if (isset($package['exclude'])) {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info[$groupindex] .= "Not Compatible with\n";
+ }
+ if (is_array($package['exclude'])) {
+ $package['exclude'] = implode(', ', $package['exclude']);
+ }
+ $info[$groupindex] .= " Package $package\n Versions " .
+ $package['exclude'];
+ }
+ }
+ }
+ }
+ }
+ }
+ if ($obj->getPackageType() == 'bundle') {
+ $info['Bundled Packages'] = '';
+ foreach ($obj->getBundledPackages() as $package) {
+ if (!empty($info['Bundled Packages'])) {
+ $info['Bundled Packages'] .= "\n";
+ }
+ if (isset($package['uri'])) {
+ $info['Bundled Packages'] .= '__uri/' . $package['name'];
+ $info['Bundled Packages'] .= "\n (URI: $package[uri]";
+ } else {
+ $info['Bundled Packages'] .= $package['channel'] . '/' . $package['name'];
+ }
+ }
+ }
+ $info['package.xml version'] = '2.0';
+ if ($installed) {
+ if ($obj->getLastModified()) {
+ $info['Last Modified'] = date('Y-m-d H:i', $obj->getLastModified());
+ }
+ $v = $obj->getLastInstalledVersion();
+ $info['Previous Installed Version'] = $v ? $v : '- None -';
+ }
+ foreach ($info as $key => $value) {
+ $data['data'][] = array($key, $value);
+ }
+ $data['raw'] = $obj->getArray(); // no validation needed
+
+ $this->ui->outputData($data, 'package-info');
+ }
+}
+
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Registry.xml b/vendor/library/Excel/phpxls/PEAR/Command/Registry.xml
new file mode 100644
index 0000000..9f4e214
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Registry.xml
@@ -0,0 +1,58 @@
+
+
+ List Installed Packages In The Default Channel
+ doList
+ l
+
+
+ c
+ list installed packages from this channel
+ CHAN
+
+
+ a
+ list installed packages from all channels
+
+
+ i
+ output fully channel-aware data, even on failure
+
+
+ <package>
+If invoked without parameters, this command lists the PEAR packages
+installed in your php_dir ({config php_dir}). With a parameter, it
+lists the files in a package.
+
+
+
+ List Files In Installed Package
+ doFileList
+ fl
+
+ <package>
+List the files in an installed package.
+
+
+
+ Shell Script Test
+ doShellTest
+ st
+
+ <package> [[relation] version]
+Tests if a package is installed in the system. Will exit(1) if it is not.
+ <relation> The version comparison operator. One of:
+ <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne
+ <version> The version to compare with
+
+
+
+ Display information about a package
+ doInfo
+ in
+
+ <package>
+Displays information about a package. The package argument may be a
+local package file, an URL to a package file, or the name of an
+installed package.
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Remote.php b/vendor/library/Excel/phpxls/PEAR/Command/Remote.php
new file mode 100644
index 0000000..c4fa908
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Remote.php
@@ -0,0 +1,812 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Remote.php,v 1.107 2008/04/11 01:16:40 dufuz Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+require_once 'PEAR/REST.php';
+
+/**
+ * PEAR commands for remote server querying
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Remote extends PEAR_Command_Common
+{
+ // {{{ command definitions
+
+ var $commands = array(
+ 'remote-info' => array(
+ 'summary' => 'Information About Remote Packages',
+ 'function' => 'doRemoteInfo',
+ 'shortcut' => 'ri',
+ 'options' => array(),
+ 'doc' => '
+Get details on a package from the server.',
+ ),
+ 'list-upgrades' => array(
+ 'summary' => 'List Available Upgrades',
+ 'function' => 'doListUpgrades',
+ 'shortcut' => 'lu',
+ 'options' => array(
+ 'channelinfo' => array(
+ 'shortopt' => 'i',
+ 'doc' => 'output fully channel-aware data, even on failure',
+ ),
+ ),
+ 'doc' => '[preferred_state]
+List releases on the server of packages you have installed where
+a newer version is available with the same release state (stable etc.)
+or the state passed as the second parameter.'
+ ),
+ 'remote-list' => array(
+ 'summary' => 'List Remote Packages',
+ 'function' => 'doRemoteList',
+ 'shortcut' => 'rl',
+ 'options' => array(
+ 'channel' =>
+ array(
+ 'shortopt' => 'c',
+ 'doc' => 'specify a channel other than the default channel',
+ 'arg' => 'CHAN',
+ )
+ ),
+ 'doc' => '
+Lists the packages available on the configured server along with the
+latest stable release of each package.',
+ ),
+ 'search' => array(
+ 'summary' => 'Search remote package database',
+ 'function' => 'doSearch',
+ 'shortcut' => 'sp',
+ 'options' => array(
+ 'channel' =>
+ array(
+ 'shortopt' => 'c',
+ 'doc' => 'specify a channel other than the default channel',
+ 'arg' => 'CHAN',
+ ),
+ 'allchannels' => array(
+ 'shortopt' => 'a',
+ 'doc' => 'search packages from all known channels',
+ ),
+ 'channelinfo' => array(
+ 'shortopt' => 'i',
+ 'doc' => 'output fully channel-aware data, even on failure',
+ ),
+ ),
+ 'doc' => '[packagename] [packageinfo]
+Lists all packages which match the search parameters. The first
+parameter is a fragment of a packagename. The default channel
+will be used unless explicitly overridden. The second parameter
+will be used to match any portion of the summary/description',
+ ),
+ 'list-all' => array(
+ 'summary' => 'List All Packages',
+ 'function' => 'doListAll',
+ 'shortcut' => 'la',
+ 'options' => array(
+ 'channel' =>
+ array(
+ 'shortopt' => 'c',
+ 'doc' => 'specify a channel other than the default channel',
+ 'arg' => 'CHAN',
+ ),
+ 'channelinfo' => array(
+ 'shortopt' => 'i',
+ 'doc' => 'output fully channel-aware data, even on failure',
+ ),
+ ),
+ 'doc' => '
+Lists the packages available on the configured server along with the
+latest stable release of each package.',
+ ),
+ 'download' => array(
+ 'summary' => 'Download Package',
+ 'function' => 'doDownload',
+ 'shortcut' => 'd',
+ 'options' => array(
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'download an uncompressed (.tar) file',
+ ),
+ ),
+ 'doc' => '...
+Download package tarballs. The files will be named as suggested by the
+server, for example if you download the DB package and the latest stable
+version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.',
+ ),
+ 'clear-cache' => array(
+ 'summary' => 'Clear Web Services Cache',
+ 'function' => 'doClearCache',
+ 'shortcut' => 'cc',
+ 'options' => array(),
+ 'doc' => '
+Clear the XML-RPC/REST cache. See also the cache_ttl configuration
+parameter.
+',
+ ),
+ );
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * PEAR_Command_Remote constructor.
+ *
+ * @access public
+ */
+ function PEAR_Command_Remote(&$ui, &$config)
+ {
+ parent::PEAR_Command_Common($ui, $config);
+ }
+
+ // }}}
+
+ function _checkChannelForStatus($channel, $chan)
+ {
+ if (PEAR::isError($chan)) {
+ $this->raiseError($chan);
+ }
+ if (!is_a($chan, 'PEAR_ChannelFile')) {
+ return $this->raiseError('Internal corruption error: invalid channel "' .
+ $channel . '"');
+ }
+ $rest = new PEAR_REST($this->config);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $mirror = $this->config->get('preferred_mirror', null,
+ $channel);
+ $a = $rest->downloadHttp('http://' . $channel .
+ '/channel.xml', $chan->lastModified());
+ PEAR::staticPopErrorHandling();
+ if (!PEAR::isError($a) && $a) {
+ $this->ui->outputData('WARNING: channel "' . $channel . '" has ' .
+ 'updated its protocols, use "channel-update ' . $channel .
+ '" to update');
+ }
+ }
+
+ // {{{ doRemoteInfo()
+
+ function doRemoteInfo($command, $options, $params)
+ {
+ if (sizeof($params) != 1) {
+ return $this->raiseError("$command expects one param: the remote package name");
+ }
+ $savechannel = $channel = $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ $package = $params[0];
+ $parsed = $reg->parsePackageName($package, $channel);
+ if (PEAR::isError($parsed)) {
+ return $this->raiseError('Invalid package name "' . $package . '"');
+ }
+
+ $channel = $parsed['channel'];
+ $this->config->set('default_channel', $channel);
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
+ return $e;
+ }
+ if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+ $rest = &$this->config->getREST('1.0', array());
+ $info = $rest->packageInfo($base, $parsed['package'], $channel);
+ } else {
+ $r = &$this->config->getRemote();
+ $info = $r->call('package.info', $parsed['package']);
+ }
+ if (PEAR::isError($info)) {
+ $this->config->set('default_channel', $savechannel);
+ return $this->raiseError($info);
+ }
+ if (!isset($info['name'])) {
+ return $this->raiseError('No remote package "' . $package . '" was found');
+ }
+
+ $installed = $reg->packageInfo($info['name'], null, $channel);
+ $info['installed'] = $installed['version'] ? $installed['version'] : '- no -';
+ if (is_array($info['installed'])) {
+ $info['installed'] = $info['installed']['release'];
+ }
+
+ $this->ui->outputData($info, $command);
+ $this->config->set('default_channel', $savechannel);
+
+ return true;
+ }
+
+ // }}}
+ // {{{ doRemoteList()
+
+ function doRemoteList($command, $options, $params)
+ {
+ $savechannel = $channel = $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ if (isset($options['channel'])) {
+ $channel = $options['channel'];
+ if ($reg->channelExists($channel)) {
+ $this->config->set('default_channel', $channel);
+ } else {
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+ }
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
+ return $e;
+ }
+ $list_options = false;
+ if ($this->config->get('preferred_state') == 'stable') {
+ $list_options = true;
+ }
+ if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))) {
+ // use faster list-all if available
+ $rest = &$this->config->getREST('1.1', array());
+ $available = $rest->listAll($base, $list_options, true, false, false, $chan->getName());
+ } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+ $rest = &$this->config->getREST('1.0', array());
+ $available = $rest->listAll($base, $list_options, true, false, false, $chan->getName());
+ } else {
+ $r = &$this->config->getRemote();
+ if ($channel == 'pear.php.net') {
+ // hack because of poor pearweb design
+ $available = $r->call('package.listAll', true, $list_options, false);
+ } else {
+ $available = $r->call('package.listAll', true, $list_options);
+ }
+ }
+ if (PEAR::isError($available)) {
+ $this->config->set('default_channel', $savechannel);
+ return $this->raiseError($available);
+ }
+ $i = $j = 0;
+ $data = array(
+ 'caption' => 'Channel ' . $channel . ' Available packages:',
+ 'border' => true,
+ 'headline' => array('Package', 'Version'),
+ 'channel' => $channel
+ );
+ if (count($available)==0) {
+ $data = '(no packages available yet)';
+ } else {
+ foreach ($available as $name => $info) {
+ $data['data'][] = array($name, (isset($info['stable']) && $info['stable'])
+ ? $info['stable'] : '-n/a-');
+ }
+ }
+ $this->ui->outputData($data, $command);
+ $this->config->set('default_channel', $savechannel);
+ return true;
+ }
+
+ // }}}
+ // {{{ doListAll()
+
+ function doListAll($command, $options, $params)
+ {
+ $savechannel = $channel = $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ if (isset($options['channel'])) {
+ $channel = $options['channel'];
+ if ($reg->channelExists($channel)) {
+ $this->config->set('default_channel', $channel);
+ } else {
+ return $this->raiseError("Channel \"$channel\" does not exist");
+ }
+ }
+ $list_options = false;
+ if ($this->config->get('preferred_state') == 'stable') {
+ $list_options = true;
+ }
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
+ return $e;
+ }
+ if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))) {
+ // use faster list-all if available
+ $rest = &$this->config->getREST('1.1', array());
+ $available = $rest->listAll($base, $list_options, false, false, false, $chan->getName());
+ } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+ $rest = &$this->config->getREST('1.0', array());
+ $available = $rest->listAll($base, $list_options, false, false, false, $chan->getName());
+ } else {
+ $r = &$this->config->getRemote();
+ if ($channel == 'pear.php.net') {
+ // hack because of poor pearweb design
+ $available = $r->call('package.listAll', true, $list_options, false);
+ } else {
+ $available = $r->call('package.listAll', true, $list_options);
+ }
+ }
+ if (PEAR::isError($available)) {
+ $this->config->set('default_channel', $savechannel);
+ return $this->raiseError('The package list could not be fetched from the remote server. Please try again. (Debug info: "' . $available->getMessage() . '")');
+ }
+ $data = array(
+ 'caption' => 'All packages [Channel ' . $channel . ']:',
+ 'border' => true,
+ 'headline' => array('Package', 'Latest', 'Local'),
+ 'channel' => $channel,
+ );
+ if (isset($options['channelinfo'])) {
+ // add full channelinfo
+ $data['caption'] = 'Channel ' . $channel . ' All packages:';
+ $data['headline'] = array('Channel', 'Package', 'Latest', 'Local',
+ 'Description', 'Dependencies');
+ }
+ $local_pkgs = $reg->listPackages($channel);
+
+ foreach ($available as $name => $info) {
+ $installed = $reg->packageInfo($name, null, $channel);
+ if (is_array($installed['version'])) {
+ $installed['version'] = $installed['version']['release'];
+ }
+ $desc = $info['summary'];
+ if (isset($params[$name])) {
+ $desc .= "\n\n".$info['description'];
+ }
+ if (isset($options['mode']))
+ {
+ if ($options['mode'] == 'installed' && !isset($installed['version'])) {
+ continue;
+ }
+ if ($options['mode'] == 'notinstalled' && isset($installed['version'])) {
+ continue;
+ }
+ if ($options['mode'] == 'upgrades'
+ && (!isset($installed['version']) || version_compare($installed['version'],
+ $info['stable'], '>='))) {
+ continue;
+ }
+ }
+ $pos = array_search(strtolower($name), $local_pkgs);
+ if ($pos !== false) {
+ unset($local_pkgs[$pos]);
+ }
+
+ if (isset($info['stable']) && !$info['stable']) {
+ $info['stable'] = null;
+ }
+
+ if (isset($options['channelinfo'])) {
+ // add full channelinfo
+ if ($info['stable'] === $info['unstable']) {
+ $state = $info['state'];
+ } else {
+ $state = 'stable';
+ }
+ $latest = $info['stable'].' ('.$state.')';
+ $local = '';
+ if (isset($installed['version'])) {
+ $inst_state = $reg->packageInfo($name, 'release_state', $channel);
+ $local = $installed['version'].' ('.$inst_state.')';
+ }
+
+ $packageinfo = array(
+ $channel,
+ $name,
+ $latest,
+ $local,
+ isset($desc) ? $desc : null,
+ isset($info['deps']) ? $info['deps'] : null,
+ );
+ } else {
+ $packageinfo = array(
+ $reg->channelAlias($channel) . '/' . $name,
+ isset($info['stable']) ? $info['stable'] : null,
+ isset($installed['version']) ? $installed['version'] : null,
+ isset($desc) ? $desc : null,
+ isset($info['deps']) ? $info['deps'] : null,
+ );
+ }
+ $data['data'][$info['category']][] = $packageinfo;
+ }
+
+ if (isset($options['mode']) && in_array($options['mode'], array('notinstalled', 'upgrades'))) {
+ $this->config->set('default_channel', $savechannel);
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+ foreach ($local_pkgs as $name) {
+ $info = &$reg->getPackage($name, $channel);
+ $data['data']['Local'][] = array(
+ $reg->channelAlias($channel) . '/' . $info->getPackage(),
+ '',
+ $info->getVersion(),
+ $info->getSummary(),
+ $info->getDeps()
+ );
+ }
+
+ $this->config->set('default_channel', $savechannel);
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ // }}}
+ // {{{ doSearch()
+
+ function doSearch($command, $options, $params)
+ {
+ if ((!isset($params[0]) || empty($params[0]))
+ && (!isset($params[1]) || empty($params[1])))
+ {
+ return $this->raiseError('no valid search string supplied');
+ };
+
+ $channelinfo = isset($options['channelinfo']);
+ $reg = &$this->config->getRegistry();
+ if (isset($options['allchannels'])) {
+ // search all channels
+ unset($options['allchannels']);
+ $channels = $reg->getChannels();
+ $errors = array();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ foreach ($channels as $channel) {
+ if ($channel->getName() != '__uri') {
+ $options['channel'] = $channel->getName();
+ $ret = $this->doSearch($command, $options, $params);
+ if (PEAR::isError($ret)) {
+ $errors[] = $ret;
+ }
+ }
+ }
+ PEAR::staticPopErrorHandling();
+ if (count($errors) !== 0) {
+ // for now, only give first error
+ return PEAR::raiseError($errors[0]);
+ }
+
+ return true;
+ }
+
+ $savechannel = $channel = $this->config->get('default_channel');
+ $package = $params[0];
+ $summary = isset($params[1]) ? $params[1] : false;
+ if (isset($options['channel'])) {
+ $reg = &$this->config->getRegistry();
+ $channel = $options['channel'];
+ if ($reg->channelExists($channel)) {
+ $this->config->set('default_channel', $channel);
+ } else {
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+ }
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
+ return $e;
+ }
+ if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+ $rest = &$this->config->getREST('1.0', array());
+ $available = $rest->listAll($base, false, false, $package, $summary, $chan->getName());
+ } else {
+ $r = &$this->config->getRemote();
+ $available = $r->call('package.search', $package, $summary, true,
+ $this->config->get('preferred_state') == 'stable', true);
+ }
+ if (PEAR::isError($available)) {
+ $this->config->set('default_channel', $savechannel);
+ return $this->raiseError($available);
+ }
+ if (!$available && !$channelinfo) {
+ // clean exit when not found, no error !
+ $data = 'no packages found that match pattern "' . $package . '", for channel '.$channel.'.';
+ $this->ui->outputData($data);
+ $this->config->set('default_channel', $channel);
+ return true;
+ }
+ if ($channelinfo) {
+ $data = array(
+ 'caption' => 'Matched packages, channel ' . $channel . ':',
+ 'border' => true,
+ 'headline' => array('Channel', 'Package', 'Stable/(Latest)', 'Local'),
+ 'channel' => $channel
+ );
+ } else {
+ $data = array(
+ 'caption' => 'Matched packages, channel ' . $channel . ':',
+ 'border' => true,
+ 'headline' => array('Package', 'Stable/(Latest)', 'Local'),
+ 'channel' => $channel
+ );
+ }
+
+ if (!$available && $channelinfo) {
+ unset($data['headline']);
+ $data['data'] = 'No packages found that match pattern "' . $package . '".';
+ $available = array();
+ }
+ foreach ($available as $name => $info) {
+ $installed = $reg->packageInfo($name, null, $channel);
+ $desc = $info['summary'];
+ if (isset($params[$name]))
+ $desc .= "\n\n".$info['description'];
+
+ if (!isset($info['stable']) || !$info['stable']) {
+ $version_remote = 'none';
+ } else {
+ if ($info['unstable']) {
+ $version_remote = $info['unstable'];
+ } else {
+ $version_remote = $info['stable'];
+ }
+ $version_remote .= ' ('.$info['state'].')';
+ }
+ $version = is_array($installed['version']) ? $installed['version']['release'] :
+ $installed['version'];
+ if ($channelinfo) {
+ $packageinfo = array(
+ $channel,
+ $name,
+ $version_remote,
+ $version,
+ $desc,
+ );
+ } else {
+ $packageinfo = array(
+ $name,
+ $version_remote,
+ $version,
+ $desc,
+ );
+ }
+ $data['data'][$info['category']][] = $packageinfo;
+ }
+ $this->ui->outputData($data, $command);
+ $this->config->set('default_channel', $channel);
+ return true;
+ }
+
+ // }}}
+ function &getDownloader($options)
+ {
+ if (!class_exists('PEAR_Downloader')) {
+ require_once 'PEAR/Downloader.php';
+ }
+ $a = &new PEAR_Downloader($this->ui, $options, $this->config);
+ return $a;
+ }
+ // {{{ doDownload()
+
+ function doDownload($command, $options, $params)
+ {
+ // make certain that dependencies are ignored
+ $options['downloadonly'] = 1;
+
+ // eliminate error messages for preferred_state-related errors
+ /* TODO: Should be an option, but until now download does respect
+ prefered state */
+ /* $options['ignorepreferred_state'] = 1; */
+ // eliminate error messages for preferred_state-related errors
+
+ $downloader = &$this->getDownloader($options);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $e = $downloader->setDownloadDir(getcwd());
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($e)) {
+ return $this->raiseError('Current directory is not writeable, cannot download');
+ }
+ $errors = array();
+ $downloaded = array();
+ $err = $downloader->download($params);
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+ $errors = $downloader->getErrorMsgs();
+ if (count($errors)) {
+ foreach ($errors as $error) {
+ $this->ui->outputData($error);
+ }
+ return $this->raiseError("$command failed");
+ }
+ $downloaded = $downloader->getDownloadedPackages();
+ foreach ($downloaded as $pkg) {
+ $this->ui->outputData("File $pkg[file] downloaded", $command);
+ }
+ return true;
+ }
+
+ function downloadCallback($msg, $params = null)
+ {
+ if ($msg == 'done') {
+ $this->bytes_downloaded = $params;
+ }
+ }
+
+ // }}}
+ // {{{ doListUpgrades()
+
+ function doListUpgrades($command, $options, $params)
+ {
+ require_once 'PEAR/Common.php';
+ if (isset($params[0]) && !is_array(PEAR_Common::betterStates($params[0]))) {
+ return $this->raiseError($params[0] . ' is not a valid state (stable/beta/alpha/devel/etc.) try "pear help list-upgrades"');
+ }
+ $savechannel = $channel = $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ foreach ($reg->listChannels() as $channel) {
+ $inst = array_flip($reg->listPackages($channel));
+ if (!count($inst)) {
+ continue;
+ }
+ if ($channel == '__uri') {
+ continue;
+ }
+ $this->config->set('default_channel', $channel);
+ if (empty($params[0])) {
+ $state = $this->config->get('preferred_state');
+ } else {
+ $state = $params[0];
+ }
+ $caption = $channel . ' Available Upgrades';
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
+ return $e;
+ }
+ if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+ $rest = &$this->config->getREST('1.0', array());
+ if (empty($state) || $state == 'any') {
+ $state = false;
+ } else {
+ $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')';
+ }
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $latest = $rest->listLatestUpgrades($base, $state, $inst, $channel, $reg);
+ PEAR::staticPopErrorHandling();
+ } else {
+ $remote = &$this->config->getRemote();
+ $remote->pushErrorHandling(PEAR_ERROR_RETURN);
+ if (empty($state) || $state == 'any') {
+ $latest = $remote->call("package.listLatestReleases");
+ } else {
+ $latest = $remote->call("package.listLatestReleases", $state);
+ $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')';
+ }
+ $remote->popErrorHandling();
+ }
+ if (PEAR::isError($latest)) {
+ $this->ui->outputData($latest->getMessage());
+ continue;
+ }
+ $caption .= ':';
+ if (PEAR::isError($latest)) {
+ $this->config->set('default_channel', $savechannel);
+ return $latest;
+ }
+ $data = array(
+ 'caption' => $caption,
+ 'border' => 1,
+ 'headline' => array('Channel', 'Package', 'Local', 'Remote', 'Size'),
+ 'channel' => $channel
+ );
+ foreach ((array)$latest as $pkg => $info) {
+ $package = strtolower($pkg);
+ if (!isset($inst[$package])) {
+ // skip packages we don't have installed
+ continue;
+ }
+ extract($info);
+ $inst_version = $reg->packageInfo($package, 'version', $channel);
+ $inst_state = $reg->packageInfo($package, 'release_state', $channel);
+ if (version_compare("$version", "$inst_version", "le")) {
+ // installed version is up-to-date
+ continue;
+ }
+ if ($filesize >= 20480) {
+ $filesize += 1024 - ($filesize % 1024);
+ $fs = sprintf("%dkB", $filesize / 1024);
+ } elseif ($filesize > 0) {
+ $filesize += 103 - ($filesize % 103);
+ $fs = sprintf("%.1fkB", $filesize / 1024.0);
+ } else {
+ $fs = " -"; // XXX center instead
+ }
+ $data['data'][] = array($channel, $pkg, "$inst_version ($inst_state)", "$version ($state)", $fs);
+ }
+ if (isset($options['channelinfo'])) {
+ if (empty($data['data'])) {
+ unset($data['headline']);
+ if (count($inst) == 0) {
+ $data['data'] = '(no packages installed)';
+ } else {
+ $data['data'] = '(no upgrades available)';
+ }
+ }
+ $this->ui->outputData($data, $command);
+ } else {
+ if (empty($data['data'])) {
+ $this->ui->outputData('Channel ' . $channel . ': No upgrades available');
+ } else {
+ $this->ui->outputData($data, $command);
+ }
+ }
+ }
+ $this->config->set('default_channel', $savechannel);
+ return true;
+ }
+
+ // }}}
+ // {{{ doClearCache()
+
+ function doClearCache($command, $options, $params)
+ {
+ $cache_dir = $this->config->get('cache_dir');
+ $verbose = $this->config->get('verbose');
+ $output = '';
+ if (!file_exists($cache_dir) || !is_dir($cache_dir)) {
+ return $this->raiseError("$cache_dir does not exist or is not a directory");
+ }
+ if (!($dp = @opendir($cache_dir))) {
+ return $this->raiseError("opendir($cache_dir) failed: $php_errormsg");
+ }
+ if ($verbose >= 1) {
+ $output .= "reading directory $cache_dir\n";
+ }
+ $num = 0;
+ while ($ent = readdir($dp)) {
+ if (preg_match('/^xmlrpc_cache_[a-z0-9]{32}\\z/', $ent) ||
+ preg_match('/rest.cache(file|id)\\z/', $ent)) {
+ $path = $cache_dir . DIRECTORY_SEPARATOR . $ent;
+ if (file_exists($path)) {
+ $ok = @unlink($path);
+ } else {
+ $ok = false;
+ $php_errormsg = '';
+ }
+ if ($ok) {
+ if ($verbose >= 2) {
+ $output .= "deleted $path\n";
+ }
+ $num++;
+ } elseif ($verbose >= 1) {
+ $output .= "failed to delete $path $php_errormsg\n";
+ }
+ }
+ }
+ closedir($dp);
+ if ($verbose >= 1) {
+ $output .= "$num cache entries cleared\n";
+ }
+ $this->ui->outputData(rtrim($output), $command);
+ return $num;
+ }
+
+ // }}}
+}
+
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Remote.xml b/vendor/library/Excel/phpxls/PEAR/Command/Remote.xml
new file mode 100644
index 0000000..d06f222
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Remote.xml
@@ -0,0 +1,108 @@
+
+
+ Information About Remote Packages
+ doRemoteInfo
+ ri
+
+ <package>
+Get details on a package from the server.
+
+
+ List Available Upgrades
+ doListUpgrades
+ lu
+
+ [preferred_state]
+List releases on the server of packages you have installed where
+a newer version is available with the same release state (stable etc.)
+or the state passed as the second parameter.
+
+
+ List Remote Packages
+ doRemoteList
+ rl
+
+
+ c
+ specify a channel other than the default channel
+ CHAN
+
+
+ i
+ output fully channel-aware data, even on failure
+
+
+
+Lists the packages available on the configured server along with the
+latest stable release of each package.
+
+
+ Search remote package database
+ doSearch
+ sp
+
+
+ c
+ specify a channel other than the default channel
+ CHAN
+
+
+ a
+ search packages from all known channels
+
+
+ i
+ output fully channel-aware data, even on failure
+
+
+ [packagename] [packageinfo]
+Lists all packages which match the search parameters. The first
+parameter is a fragment of a packagename. The default channel
+will be used unless explicitly overridden. The second parameter
+will be used to match any portion of the summary/description
+
+
+ List All Packages
+ doListAll
+ la
+
+
+ c
+ specify a channel other than the default channel
+ CHAN
+
+
+ i
+ output fully channel-aware data, even on failure
+
+
+
+Lists the packages available on the configured server along with the
+latest stable release of each package.
+
+
+ Download Package
+ doDownload
+ d
+
+
+ Z
+ download an uncompressed (.tar) file
+
+
+ <package>...
+Download package tarballs. The files will be named as suggested by the
+server, for example if you download the DB package and the latest stable
+version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.
+
+
+ Clear Web Services Cache
+ doClearCache
+ cc
+
+
+Clear the XML-RPC/REST cache. See also the cache_ttl configuration
+parameter.
+
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Test.php b/vendor/library/Excel/phpxls/PEAR/Command/Test.php
new file mode 100644
index 0000000..4cf40f6
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Test.php
@@ -0,0 +1,345 @@
+
+ * @author Martin Jansen
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Test.php,v 1.27 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for login/logout
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Martin Jansen
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+
+class PEAR_Command_Test extends PEAR_Command_Common
+{
+ // {{{ properties
+
+ var $commands = array(
+ 'run-tests' => array(
+ 'summary' => 'Run Regression Tests',
+ 'function' => 'doRunTests',
+ 'shortcut' => 'rt',
+ 'options' => array(
+ 'recur' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'Run tests in child directories, recursively. 4 dirs deep maximum',
+ ),
+ 'ini' => array(
+ 'shortopt' => 'i',
+ 'doc' => 'actual string of settings to pass to php in format " -d setting=blah"',
+ 'arg' => 'SETTINGS'
+ ),
+ 'realtimelog' => array(
+ 'shortopt' => 'l',
+ 'doc' => 'Log test runs/results as they are run',
+ ),
+ 'quiet' => array(
+ 'shortopt' => 'q',
+ 'doc' => 'Only display detail for failed tests',
+ ),
+ 'simple' => array(
+ 'shortopt' => 's',
+ 'doc' => 'Display simple output for all tests',
+ ),
+ 'package' => array(
+ 'shortopt' => 'p',
+ 'doc' => 'Treat parameters as installed packages from which to run tests',
+ ),
+ 'phpunit' => array(
+ 'shortopt' => 'u',
+ 'doc' => 'Search parameters for AllTests.php, and use that to run phpunit-based tests
+If none is found, all .phpt tests will be tried instead.',
+ ),
+ 'tapoutput' => array(
+ 'shortopt' => 't',
+ 'doc' => 'Output run-tests.log in TAP-compliant format',
+ ),
+ 'cgi' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'CGI php executable (needed for tests with POST/GET section)',
+ 'arg' => 'PHPCGI',
+ ),
+ 'coverage' => array(
+ 'shortopt' => 'x',
+ 'doc' => 'Generate a code coverage report (requires Xdebug 2.0.0+)',
+ ),
+ ),
+ 'doc' => '[testfile|dir ...]
+Run regression tests with PHP\'s regression testing script (run-tests.php).',
+ ),
+ );
+
+ var $output;
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * PEAR_Command_Test constructor.
+ *
+ * @access public
+ */
+ function PEAR_Command_Test(&$ui, &$config)
+ {
+ parent::PEAR_Command_Common($ui, $config);
+ }
+
+ // }}}
+ // {{{ doRunTests()
+
+ function doRunTests($command, $options, $params)
+ {
+ if (isset($options['phpunit']) && isset($options['tapoutput'])) {
+ return $this->raiseError('ERROR: cannot use both --phpunit and --tapoutput at the same time');
+ }
+ require_once 'PEAR/Common.php';
+ require_once 'System.php';
+ $log = new PEAR_Common;
+ $log->ui = &$this->ui; // slightly hacky, but it will work
+ $tests = array();
+ $depth = isset($options['recur']) ? 4 : 1;
+
+ if (!count($params)) {
+ $params[] = '.';
+ }
+ if (isset($options['package'])) {
+ $oldparams = $params;
+ $params = array();
+ $reg = &$this->config->getRegistry();
+ foreach ($oldparams as $param) {
+ $pname = $reg->parsePackageName($param, $this->config->get('default_channel'));
+ if (PEAR::isError($pname)) {
+ return $this->raiseError($pname);
+ }
+
+ $package = &$reg->getPackage($pname['package'], $pname['channel']);
+ if (!$package) {
+ return PEAR::raiseError('Unknown package "' .
+ $reg->parsedPackageNameToString($pname) . '"');
+ }
+
+ $filelist = $package->getFilelist();
+ foreach ($filelist as $name => $atts) {
+ if (isset($atts['role']) && $atts['role'] != 'test') {
+ continue;
+ }
+
+ if (isset($options['phpunit']) && preg_match('/AllTests\.php\\z/i', $name)) {
+ $params[] = $atts['installed_as'];
+ continue;
+ } elseif (!preg_match('/\.phpt\\z/', $name)) {
+ continue;
+ }
+ $params[] = $atts['installed_as'];
+ }
+ }
+ }
+
+ foreach ($params as $p) {
+ if (is_dir($p)) {
+ if (isset($options['phpunit'])) {
+ $dir = System::find(array($p, '-type', 'f',
+ '-maxdepth', $depth,
+ '-name', 'AllTests.php'));
+ if (count($dir)) {
+ foreach ($dir as $p) {
+ $p = realpath($p);
+ if (!count($tests) ||
+ (count($tests) && strlen($p) < strlen($tests[0]))) {
+ // this is in a higher-level directory, use this one instead.
+ $tests = array($p);
+ }
+ }
+ }
+ continue;
+ }
+ $dir = System::find(array($p, '-type', 'f',
+ '-maxdepth', $depth,
+ '-name', '*.phpt'));
+ $tests = array_merge($tests, $dir);
+ } else {
+ if (isset($options['phpunit'])) {
+ if (preg_match('/AllTests\.php\\z/i', $p)) {
+ $p = realpath($p);
+ if (!count($tests) ||
+ (count($tests) && strlen($p) < strlen($tests[0]))) {
+ // this is in a higher-level directory, use this one instead.
+ $tests = array($p);
+ }
+ }
+ continue;
+ }
+
+ if (file_exists($p) && preg_match('/\.phpt$/', $p)) {
+ $tests[] = $p;
+ continue;
+ }
+
+ if (!preg_match('/\.phpt\\z/', $p)) {
+ $p .= '.phpt';
+ }
+ $dir = System::find(array(dirname($p), '-type', 'f',
+ '-maxdepth', $depth,
+ '-name', $p));
+ $tests = array_merge($tests, $dir);
+ }
+ }
+
+ $ini_settings = '';
+ if (isset($options['ini'])) {
+ $ini_settings .= $options['ini'];
+ }
+
+ if (isset($_ENV['TEST_PHP_INCLUDE_PATH'])) {
+ $ini_settings .= " -d include_path={$_ENV['TEST_PHP_INCLUDE_PATH']}";
+ }
+
+ if ($ini_settings) {
+ $this->ui->outputData('Using INI settings: "' . $ini_settings . '"');
+ }
+ $skipped = $passed = $failed = array();
+ $tests_count = count($tests);
+ $this->ui->outputData('Running ' . $tests_count . ' tests', $command);
+ $start = time();
+ if (isset($options['realtimelog']) && file_exists('run-tests.log')) {
+ unlink('run-tests.log');
+ }
+
+ if (isset($options['tapoutput'])) {
+ $tap = '1..' . $tests_count . "\n";
+ }
+
+ require_once 'PEAR/RunTest.php';
+ $run = new PEAR_RunTest($log, $options);
+ $run->tests_count = $tests_count;
+
+ if (isset($options['coverage']) && extension_loaded('xdebug')){
+ $run->xdebug_loaded = true;
+ } else {
+ $run->xdebug_loaded = false;
+ }
+
+ $j = $i = 1;
+ foreach ($tests as $t) {
+ if (isset($options['realtimelog'])) {
+ $fp = @fopen('run-tests.log', 'a');
+ if ($fp) {
+ fwrite($fp, "Running test [$i / $tests_count] $t...");
+ fclose($fp);
+ }
+ }
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ if (isset($options['phpunit'])) {
+ $result = $run->runPHPUnit($t, $ini_settings);
+ } else {
+ $result = $run->run($t, $ini_settings, $j);
+ }
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($result)) {
+ $this->ui->log($result->getMessage());
+ continue;
+ }
+
+ if (isset($options['tapoutput'])) {
+ $tap .= $result[0] . ' ' . $i . $result[1] . "\n";
+ continue;
+ }
+
+ if (isset($options['realtimelog'])) {
+ $fp = @fopen('run-tests.log', 'a');
+ if ($fp) {
+ fwrite($fp, "$result\n");
+ fclose($fp);
+ }
+ }
+
+ if ($result == 'FAILED') {
+ $failed[] = $t;
+ }
+ if ($result == 'PASSED') {
+ $passed[] = $t;
+ }
+ if ($result == 'SKIPPED') {
+ $skipped[] = $t;
+ }
+
+ $j++;
+ }
+
+ $total = date('i:s', time() - $start);
+ if (isset($options['tapoutput'])) {
+ $fp = @fopen('run-tests.log', 'w');
+ if ($fp) {
+ fwrite($fp, $tap, strlen($tap));
+ fclose($fp);
+ $this->ui->outputData('wrote TAP-format log to "' .realpath('run-tests.log') .
+ '"', $command);
+ }
+ } else {
+ if (count($failed)) {
+ $output = "TOTAL TIME: $total\n";
+ $output .= count($passed) . " PASSED TESTS\n";
+ $output .= count($skipped) . " SKIPPED TESTS\n";
+ $output .= count($failed) . " FAILED TESTS:\n";
+ foreach ($failed as $failure) {
+ $output .= $failure . "\n";
+ }
+
+ $mode = isset($options['realtimelog']) ? 'a' : 'w';
+ $fp = @fopen('run-tests.log', $mode);
+
+ if ($fp) {
+ fwrite($fp, $output, strlen($output));
+ fclose($fp);
+ $this->ui->outputData('wrote log to "' . realpath('run-tests.log') . '"', $command);
+ }
+ } elseif (file_exists('run-tests.log') && !is_dir('run-tests.log')) {
+ @unlink('run-tests.log');
+ }
+ }
+ $this->ui->outputData('TOTAL TIME: ' . $total);
+ $this->ui->outputData(count($passed) . ' PASSED TESTS', $command);
+ $this->ui->outputData(count($skipped) . ' SKIPPED TESTS', $command);
+ if (count($failed)) {
+ $this->ui->outputData(count($failed) . ' FAILED TESTS:', $command);
+ foreach ($failed as $failure) {
+ $this->ui->outputData($failure, $command);
+ }
+ }
+
+ return true;
+ }
+ // }}}
+}
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Command/Test.xml b/vendor/library/Excel/phpxls/PEAR/Command/Test.xml
new file mode 100644
index 0000000..68e8f53
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Command/Test.xml
@@ -0,0 +1,54 @@
+
+
+ Run Regression Tests
+ doRunTests
+ rt
+
+
+ r
+ Run tests in child directories, recursively. 4 dirs deep maximum
+
+
+ i
+ actual string of settings to pass to php in format " -d setting=blah"
+ SETTINGS
+
+
+ l
+ Log test runs/results as they are run
+
+
+ q
+ Only display detail for failed tests
+
+
+ s
+ Display simple output for all tests
+
+
+ p
+ Treat parameters as installed packages from which to run tests
+
+
+ u
+ Search parameters for AllTests.php, and use that to run phpunit-based tests.
+If none is found, all .phpt tests will be tried instead.
+
+
+ t
+ Output run-tests.log in TAP-compliant format
+
+
+ c
+ CGI php executable (needed for tests with POST/GET section)
+ PHPCGI
+
+
+ x
+ Generate a code coverage report (requires Xdebug 2.0.0+)
+
+
+ [testfile|dir ...]
+Run regression tests with PHP's regression testing script (run-tests.php).
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Common.php b/vendor/library/Excel/phpxls/PEAR/Common.php
new file mode 100644
index 0000000..6157362
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Common.php
@@ -0,0 +1,1126 @@
+
+ * @author Tomas V. V. Cox
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Common.php,v 1.160 2008/01/03 20:26:34 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1.0
+ * @deprecated File deprecated since Release 1.4.0a1
+ */
+
+/**
+ * Include error handling
+ */
+require_once 'PEAR.php';
+
+// {{{ constants and globals
+
+/**
+ * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode()
+ */
+define('PEAR_COMMON_ERROR_INVALIDPHP', 1);
+define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+');
+define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/');
+
+// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1
+define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?');
+define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i');
+
+// XXX far from perfect :-)
+define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG .
+ ')(-([.0-9a-zA-Z]+))?');
+define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG .
+ '\\z/');
+
+define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+');
+define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/');
+
+// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED
+define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*');
+define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i');
+
+define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/('
+ . _PEAR_COMMON_PACKAGE_NAME_PREG . ')');
+define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i');
+
+define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::('
+ . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?');
+define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/');
+
+/**
+ * List of temporary files and directories registered by
+ * PEAR_Common::addTempFile().
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_tempfiles'] = array();
+
+/**
+ * Valid maintainer roles
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper');
+
+/**
+ * Valid release states
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel');
+
+/**
+ * Valid dependency types
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi');
+
+/**
+ * Valid dependency relations
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne');
+
+/**
+ * Valid file roles
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script');
+
+/**
+ * Valid replacement types
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info');
+
+/**
+ * Valid "provide" types
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api');
+
+/**
+ * Valid "provide" types
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup');
+
+// }}}
+
+/**
+ * Class providing common functionality for PEAR administration classes.
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Tomas V. V. Cox
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ * @deprecated This class will disappear, and its components will be spread
+ * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1
+ */
+class PEAR_Common extends PEAR
+{
+ // {{{ properties
+
+ /** stack of elements, gives some sort of XML context */
+ var $element_stack = array();
+
+ /** name of currently parsed XML element */
+ var $current_element;
+
+ /** array of attributes of the currently parsed XML element */
+ var $current_attributes = array();
+
+ /** assoc with information about a package */
+ var $pkginfo = array();
+
+ /**
+ * User Interface object (PEAR_Frontend_* class). If null,
+ * the log() method uses print.
+ * @var object
+ */
+ var $ui = null;
+
+ /**
+ * Configuration object (PEAR_Config).
+ * @var PEAR_Config
+ */
+ var $config = null;
+
+ var $current_path = null;
+
+ /**
+ * PEAR_SourceAnalyzer instance
+ * @var object
+ */
+ var $source_analyzer = null;
+ /**
+ * Flag variable used to mark a valid package file
+ * @var boolean
+ * @access private
+ */
+ var $_validPackageFile;
+
+ // }}}
+
+ // {{{ constructor
+
+ /**
+ * PEAR_Common constructor
+ *
+ * @access public
+ */
+ function PEAR_Common()
+ {
+ parent::PEAR();
+ $this->config = &PEAR_Config::singleton();
+ $this->debug = $this->config->get('verbose');
+ }
+
+ // }}}
+ // {{{ destructor
+
+ /**
+ * PEAR_Common destructor
+ *
+ * @access private
+ */
+ function _PEAR_Common()
+ {
+ // doesn't work due to bug #14744
+ //$tempfiles = $this->_tempfiles;
+ $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles'];
+ while ($file = array_shift($tempfiles)) {
+ if (@is_dir($file)) {
+ if (!class_exists('System')) {
+ require_once 'System.php';
+ }
+ System::rm(array('-rf', $file));
+ } elseif (file_exists($file)) {
+ unlink($file);
+ }
+ }
+ }
+
+ // }}}
+ // {{{ addTempFile()
+
+ /**
+ * Register a temporary file or directory. When the destructor is
+ * executed, all registered temporary files and directories are
+ * removed.
+ *
+ * @param string $file name of file or directory
+ *
+ * @return void
+ *
+ * @access public
+ */
+ function addTempFile($file)
+ {
+ if (!class_exists('PEAR_Frontend')) {
+ require_once 'PEAR/Frontend.php';
+ }
+ PEAR_Frontend::addTempFile($file);
+ }
+
+ // }}}
+ // {{{ mkDirHier()
+
+ /**
+ * Wrapper to System::mkDir(), creates a directory as well as
+ * any necessary parent directories.
+ *
+ * @param string $dir directory name
+ *
+ * @return bool TRUE on success, or a PEAR error
+ *
+ * @access public
+ */
+ function mkDirHier($dir)
+ {
+ $this->log(2, "+ create dir $dir");
+ if (!class_exists('System')) {
+ require_once 'System.php';
+ }
+ return System::mkDir(array('-p', $dir));
+ }
+
+ // }}}
+ // {{{ log()
+
+ /**
+ * Logging method.
+ *
+ * @param int $level log level (0 is quiet, higher is noisier)
+ * @param string $msg message to write to the log
+ *
+ * @return void
+ *
+ * @access public
+ * @static
+ */
+ static function log($level, $msg, $append_crlf = true)
+ {
+ if ($this->debug >= $level) {
+ if (!class_exists('PEAR_Frontend')) {
+ require_once 'PEAR/Frontend.php';
+ }
+ $ui = &PEAR_Frontend::singleton();
+ if (is_a($ui, 'PEAR_Frontend')) {
+ $ui->log($msg, $append_crlf);
+ } else {
+ print "$msg\n";
+ }
+ }
+ }
+
+ // }}}
+ // {{{ mkTempDir()
+
+ /**
+ * Create and register a temporary directory.
+ *
+ * @param string $tmpdir (optional) Directory to use as tmpdir.
+ * Will use system defaults (for example
+ * /tmp or c:\windows\temp) if not specified
+ *
+ * @return string name of created directory
+ *
+ * @access public
+ */
+ function mkTempDir($tmpdir = '')
+ {
+ if ($tmpdir) {
+ $topt = array('-t', $tmpdir);
+ } else {
+ $topt = array();
+ }
+ $topt = array_merge($topt, array('-d', 'pear'));
+ if (!class_exists('System')) {
+ require_once 'System.php';
+ }
+ if (!$tmpdir = System::mktemp($topt)) {
+ return false;
+ }
+ $this->addTempFile($tmpdir);
+ return $tmpdir;
+ }
+
+ // }}}
+ // {{{ setFrontendObject()
+
+ /**
+ * Set object that represents the frontend to be used.
+ *
+ * @param object Reference of the frontend object
+ * @return void
+ * @access public
+ */
+ function setFrontendObject(&$ui)
+ {
+ $this->ui = &$ui;
+ }
+
+ // }}}
+
+ // {{{ infoFromTgzFile()
+
+ /**
+ * Returns information about a package file. Expects the name of
+ * a gzipped tar file as input.
+ *
+ * @param string $file name of .tgz file
+ *
+ * @return array array with package information
+ *
+ * @access public
+ * @deprecated use PEAR_PackageFile->fromTgzFile() instead
+ *
+ */
+ function infoFromTgzFile($file)
+ {
+ $packagefile = &new PEAR_PackageFile($this->config);
+ $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($pf)) {
+ $errs = $pf->getUserinfo();
+ if (is_array($errs)) {
+ foreach ($errs as $error) {
+ $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
+ }
+ }
+ return $pf;
+ }
+ return $this->_postProcessValidPackagexml($pf);
+ }
+
+ // }}}
+ // {{{ infoFromDescriptionFile()
+
+ /**
+ * Returns information about a package file. Expects the name of
+ * a package xml file as input.
+ *
+ * @param string $descfile name of package xml file
+ *
+ * @return array array with package information
+ *
+ * @access public
+ * @deprecated use PEAR_PackageFile->fromPackageFile() instead
+ *
+ */
+ function infoFromDescriptionFile($descfile)
+ {
+ $packagefile = &new PEAR_PackageFile($this->config);
+ $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($pf)) {
+ $errs = $pf->getUserinfo();
+ if (is_array($errs)) {
+ foreach ($errs as $error) {
+ $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
+ }
+ }
+ return $pf;
+ }
+ return $this->_postProcessValidPackagexml($pf);
+ }
+
+ // }}}
+ // {{{ infoFromString()
+
+ /**
+ * Returns information about a package file. Expects the contents
+ * of a package xml file as input.
+ *
+ * @param string $data contents of package.xml file
+ *
+ * @return array array with package information
+ *
+ * @access public
+ * @deprecated use PEAR_PackageFile->fromXmlstring() instead
+ *
+ */
+ function infoFromString($data)
+ {
+ $packagefile = &new PEAR_PackageFile($this->config);
+ $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false);
+ if (PEAR::isError($pf)) {
+ $errs = $pf->getUserinfo();
+ if (is_array($errs)) {
+ foreach ($errs as $error) {
+ $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
+ }
+ }
+ return $pf;
+ }
+ return $this->_postProcessValidPackagexml($pf);
+ }
+ // }}}
+
+ /**
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @return array
+ */
+ function _postProcessValidPackagexml(&$pf)
+ {
+ if (is_a($pf, 'PEAR_PackageFile_v2')) {
+ // sort of make this into a package.xml 1.0-style array
+ // changelog is not converted to old format.
+ $arr = $pf->toArray(true);
+ $arr = array_merge($arr, $arr['old']);
+ unset($arr['old']);
+ unset($arr['xsdversion']);
+ unset($arr['contents']);
+ unset($arr['compatible']);
+ unset($arr['channel']);
+ unset($arr['uri']);
+ unset($arr['dependencies']);
+ unset($arr['phprelease']);
+ unset($arr['extsrcrelease']);
+ unset($arr['zendextsrcrelease']);
+ unset($arr['extbinrelease']);
+ unset($arr['zendextbinrelease']);
+ unset($arr['bundle']);
+ unset($arr['lead']);
+ unset($arr['developer']);
+ unset($arr['helper']);
+ unset($arr['contributor']);
+ $arr['filelist'] = $pf->getFilelist();
+ $this->pkginfo = $arr;
+ return $arr;
+ } else {
+ $this->pkginfo = $pf->toArray();
+ return $this->pkginfo;
+ }
+ }
+ // {{{ infoFromAny()
+
+ /**
+ * Returns package information from different sources
+ *
+ * This method is able to extract information about a package
+ * from a .tgz archive or from a XML package definition file.
+ *
+ * @access public
+ * @param string Filename of the source ('package.xml', '.tgz')
+ * @return string
+ * @deprecated use PEAR_PackageFile->fromAnyFile() instead
+ */
+ function infoFromAny($info)
+ {
+ if (is_string($info) && file_exists($info)) {
+ $packagefile = &new PEAR_PackageFile($this->config);
+ $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($pf)) {
+ $errs = $pf->getUserinfo();
+ if (is_array($errs)) {
+ foreach ($errs as $error) {
+ $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
+ }
+ }
+ return $pf;
+ }
+ return $this->_postProcessValidPackagexml($pf);
+ }
+ return $info;
+ }
+
+ // }}}
+ // {{{ xmlFromInfo()
+
+ /**
+ * Return an XML document based on the package info (as returned
+ * by the PEAR_Common::infoFrom* methods).
+ *
+ * @param array $pkginfo package info
+ *
+ * @return string XML data
+ *
+ * @access public
+ * @deprecated use a PEAR_PackageFile_v* object's generator instead
+ */
+ function xmlFromInfo($pkginfo)
+ {
+ $config = &PEAR_Config::singleton();
+ $packagefile = &new PEAR_PackageFile($config);
+ $pf = &$packagefile->fromArray($pkginfo);
+ $gen = &$pf->getDefaultGenerator();
+ return $gen->toXml(PEAR_VALIDATE_PACKAGING);
+ }
+
+ // }}}
+ // {{{ validatePackageInfo()
+
+ /**
+ * Validate XML package definition file.
+ *
+ * @param string $info Filename of the package archive or of the
+ * package definition file
+ * @param array $errors Array that will contain the errors
+ * @param array $warnings Array that will contain the warnings
+ * @param string $dir_prefix (optional) directory where source files
+ * may be found, or empty if they are not available
+ * @access public
+ * @return boolean
+ * @deprecated use the validation of PEAR_PackageFile objects
+ */
+ function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '')
+ {
+ $config = &PEAR_Config::singleton();
+ $packagefile = &new PEAR_PackageFile($config);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ if (strpos($info, 'fromXmlString($info, PEAR_VALIDATE_NORMAL, '');
+ } else {
+ $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
+ }
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($pf)) {
+ $errs = $pf->getUserinfo();
+ if (is_array($errs)) {
+ foreach ($errs as $error) {
+ if ($error['level'] == 'error') {
+ $errors[] = $error['message'];
+ } else {
+ $warnings[] = $error['message'];
+ }
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ buildProvidesArray()
+
+ /**
+ * Build a "provides" array from data returned by
+ * analyzeSourceCode(). The format of the built array is like
+ * this:
+ *
+ * array(
+ * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
+ * ...
+ * )
+ *
+ *
+ * @param array $srcinfo array with information about a source file
+ * as returned by the analyzeSourceCode() method.
+ *
+ * @return void
+ *
+ * @access public
+ *
+ */
+ function buildProvidesArray($srcinfo)
+ {
+ $file = basename($srcinfo['source_file']);
+ $pn = '';
+ if (isset($this->_packageName)) {
+ $pn = $this->_packageName;
+ }
+ $pnl = strlen($pn);
+ foreach ($srcinfo['declared_classes'] as $class) {
+ $key = "class;$class";
+ if (isset($this->pkginfo['provides'][$key])) {
+ continue;
+ }
+ $this->pkginfo['provides'][$key] =
+ array('file'=> $file, 'type' => 'class', 'name' => $class);
+ if (isset($srcinfo['inheritance'][$class])) {
+ $this->pkginfo['provides'][$key]['extends'] =
+ $srcinfo['inheritance'][$class];
+ }
+ }
+ foreach ($srcinfo['declared_methods'] as $class => $methods) {
+ foreach ($methods as $method) {
+ $function = "$class::$method";
+ $key = "function;$function";
+ if ($method{0} == '_' || !strcasecmp($method, $class) ||
+ isset($this->pkginfo['provides'][$key])) {
+ continue;
+ }
+ $this->pkginfo['provides'][$key] =
+ array('file'=> $file, 'type' => 'function', 'name' => $function);
+ }
+ }
+
+ foreach ($srcinfo['declared_functions'] as $function) {
+ $key = "function;$function";
+ if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) {
+ continue;
+ }
+ if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
+ $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
+ }
+ $this->pkginfo['provides'][$key] =
+ array('file'=> $file, 'type' => 'function', 'name' => $function);
+ }
+ }
+
+ // }}}
+ // {{{ analyzeSourceCode()
+
+ /**
+ * Analyze the source code of the given PHP file
+ *
+ * @param string Filename of the PHP file
+ * @return mixed
+ * @access public
+ */
+ function analyzeSourceCode($file)
+ {
+ if (!function_exists("token_get_all")) {
+ return false;
+ }
+ if (!defined('T_DOC_COMMENT')) {
+ define('T_DOC_COMMENT', T_COMMENT);
+ }
+ if (!defined('T_INTERFACE')) {
+ define('T_INTERFACE', -1);
+ }
+ if (!defined('T_IMPLEMENTS')) {
+ define('T_IMPLEMENTS', -1);
+ }
+ if (!$fp = @fopen($file, "r")) {
+ return false;
+ }
+ fclose($fp);
+ $contents = file_get_contents($file);
+ $tokens = token_get_all($contents);
+/*
+ for ($i = 0; $i < sizeof($tokens); $i++) {
+ @list($token, $data) = $tokens[$i];
+ if (is_string($token)) {
+ var_dump($token);
+ } else {
+ print token_name($token) . ' ';
+ var_dump(rtrim($data));
+ }
+ }
+*/
+ $look_for = 0;
+ $paren_level = 0;
+ $bracket_level = 0;
+ $brace_level = 0;
+ $lastphpdoc = '';
+ $current_class = '';
+ $current_interface = '';
+ $current_class_level = -1;
+ $current_function = '';
+ $current_function_level = -1;
+ $declared_classes = array();
+ $declared_interfaces = array();
+ $declared_functions = array();
+ $declared_methods = array();
+ $used_classes = array();
+ $used_functions = array();
+ $extends = array();
+ $implements = array();
+ $nodeps = array();
+ $inquote = false;
+ $interface = false;
+ for ($i = 0; $i < sizeof($tokens); $i++) {
+ if (is_array($tokens[$i])) {
+ list($token, $data) = $tokens[$i];
+ } else {
+ $token = $tokens[$i];
+ $data = '';
+ }
+ if ($inquote) {
+ if ($token != '"') {
+ continue;
+ } else {
+ $inquote = false;
+ continue;
+ }
+ }
+ switch ($token) {
+ case T_WHITESPACE:
+ continue;
+ case ';':
+ if ($interface) {
+ $current_function = '';
+ $current_function_level = -1;
+ }
+ break;
+ case '"':
+ $inquote = true;
+ break;
+ case T_CURLY_OPEN:
+ case T_DOLLAR_OPEN_CURLY_BRACES:
+ case '{': $brace_level++; continue 2;
+ case '}':
+ $brace_level--;
+ if ($current_class_level == $brace_level) {
+ $current_class = '';
+ $current_class_level = -1;
+ }
+ if ($current_function_level == $brace_level) {
+ $current_function = '';
+ $current_function_level = -1;
+ }
+ continue 2;
+ case '[': $bracket_level++; continue 2;
+ case ']': $bracket_level--; continue 2;
+ case '(': $paren_level++; continue 2;
+ case ')': $paren_level--; continue 2;
+ case T_INTERFACE:
+ $interface = true;
+ case T_CLASS:
+ if (($current_class_level != -1) || ($current_function_level != -1)) {
+ PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
+ PEAR_COMMON_ERROR_INVALIDPHP);
+ return false;
+ }
+ case T_FUNCTION:
+ case T_NEW:
+ case T_EXTENDS:
+ case T_IMPLEMENTS:
+ $look_for = $token;
+ continue 2;
+ case T_STRING:
+ if (version_compare(zend_version(), '2.0', '<')) {
+ if (in_array(strtolower($data),
+ array('public', 'private', 'protected', 'abstract',
+ 'interface', 'implements', 'throw')
+ )) {
+ PEAR::raiseError('Error: PHP5 token encountered in ' . $file .
+ 'packaging should be done in PHP 5');
+ return false;
+ }
+ }
+ if ($look_for == T_CLASS) {
+ $current_class = $data;
+ $current_class_level = $brace_level;
+ $declared_classes[] = $current_class;
+ } elseif ($look_for == T_INTERFACE) {
+ $current_interface = $data;
+ $current_class_level = $brace_level;
+ $declared_interfaces[] = $current_interface;
+ } elseif ($look_for == T_IMPLEMENTS) {
+ $implements[$current_class] = $data;
+ } elseif ($look_for == T_EXTENDS) {
+ $extends[$current_class] = $data;
+ } elseif ($look_for == T_FUNCTION) {
+ if ($current_class) {
+ $current_function = "$current_class::$data";
+ $declared_methods[$current_class][] = $data;
+ } elseif ($current_interface) {
+ $current_function = "$current_interface::$data";
+ $declared_methods[$current_interface][] = $data;
+ } else {
+ $current_function = $data;
+ $declared_functions[] = $current_function;
+ }
+ $current_function_level = $brace_level;
+ $m = array();
+ } elseif ($look_for == T_NEW) {
+ $used_classes[$data] = true;
+ }
+ $look_for = 0;
+ continue 2;
+ case T_VARIABLE:
+ $look_for = 0;
+ continue 2;
+ case T_DOC_COMMENT:
+ case T_COMMENT:
+ if (preg_match('!^/\*\*\s!', $data)) {
+ $lastphpdoc = $data;
+ if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
+ $nodeps = array_merge($nodeps, $m[1]);
+ }
+ }
+ continue 2;
+ case T_DOUBLE_COLON:
+ if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
+ PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
+ PEAR_COMMON_ERROR_INVALIDPHP);
+ return false;
+ }
+ $class = $tokens[$i - 1][1];
+ if (strtolower($class) != 'parent') {
+ $used_classes[$class] = true;
+ }
+ continue 2;
+ }
+ }
+ return array(
+ "source_file" => $file,
+ "declared_classes" => $declared_classes,
+ "declared_interfaces" => $declared_interfaces,
+ "declared_methods" => $declared_methods,
+ "declared_functions" => $declared_functions,
+ "used_classes" => array_diff(array_keys($used_classes), $nodeps),
+ "inheritance" => $extends,
+ "implements" => $implements,
+ );
+ }
+
+ // }}}
+ // {{{ betterStates()
+
+ /**
+ * Return an array containing all of the states that are more stable than
+ * or equal to the passed in state
+ *
+ * @param string Release state
+ * @param boolean Determines whether to include $state in the list
+ * @return false|array False if $state is not a valid release state
+ */
+ function betterStates($state, $include = false)
+ {
+ static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
+ $i = array_search($state, $states);
+ if ($i === false) {
+ return false;
+ }
+ if ($include) {
+ $i--;
+ }
+ return array_slice($states, $i + 1);
+ }
+
+ // }}}
+ // {{{ detectDependencies()
+
+ function detectDependencies($any, $status_callback = null)
+ {
+ if (!function_exists("token_get_all")) {
+ return false;
+ }
+ if (PEAR::isError($info = $this->infoFromAny($any))) {
+ return $this->raiseError($info);
+ }
+ if (!is_array($info)) {
+ return false;
+ }
+ $deps = array();
+ $used_c = $decl_c = $decl_f = $decl_m = array();
+ foreach ($info['filelist'] as $file => $fa) {
+ $tmp = $this->analyzeSourceCode($file);
+ $used_c = @array_merge($used_c, $tmp['used_classes']);
+ $decl_c = @array_merge($decl_c, $tmp['declared_classes']);
+ $decl_f = @array_merge($decl_f, $tmp['declared_functions']);
+ $decl_m = @array_merge($decl_m, $tmp['declared_methods']);
+ $inheri = @array_merge($inheri, $tmp['inheritance']);
+ }
+ $used_c = array_unique($used_c);
+ $decl_c = array_unique($decl_c);
+ $undecl_c = array_diff($used_c, $decl_c);
+ return array('used_classes' => $used_c,
+ 'declared_classes' => $decl_c,
+ 'declared_methods' => $decl_m,
+ 'declared_functions' => $decl_f,
+ 'undeclared_classes' => $undecl_c,
+ 'inheritance' => $inheri,
+ );
+ }
+
+ // }}}
+ // {{{ getUserRoles()
+
+ /**
+ * Get the valid roles for a PEAR package maintainer
+ *
+ * @return array
+ * @static
+ */
+ static function getUserRoles()
+ {
+ return $GLOBALS['_PEAR_Common_maintainer_roles'];
+ }
+
+ // }}}
+ // {{{ getReleaseStates()
+
+ /**
+ * Get the valid package release states of packages
+ *
+ * @return array
+ * @static
+ */
+ static function getReleaseStates()
+ {
+ return $GLOBALS['_PEAR_Common_release_states'];
+ }
+
+ // }}}
+ // {{{ getDependencyTypes()
+
+ /**
+ * Get the implemented dependency types (php, ext, pkg etc.)
+ *
+ * @return array
+ * @static
+ */
+ static function getDependencyTypes()
+ {
+ return $GLOBALS['_PEAR_Common_dependency_types'];
+ }
+
+ // }}}
+ // {{{ getDependencyRelations()
+
+ /**
+ * Get the implemented dependency relations (has, lt, ge etc.)
+ *
+ * @return array
+ * @static
+ */
+ static function getDependencyRelations()
+ {
+ return $GLOBALS['_PEAR_Common_dependency_relations'];
+ }
+
+ // }}}
+ // {{{ getFileRoles()
+
+ /**
+ * Get the implemented file roles
+ *
+ * @return array
+ * @static
+ */
+ static function getFileRoles()
+ {
+ return $GLOBALS['_PEAR_Common_file_roles'];
+ }
+
+ // }}}
+ // {{{ getReplacementTypes()
+
+ /**
+ * Get the implemented file replacement types in
+ *
+ * @return array
+ * @static
+ */
+ static function getReplacementTypes()
+ {
+ return $GLOBALS['_PEAR_Common_replacement_types'];
+ }
+
+ // }}}
+ // {{{ getProvideTypes()
+
+ /**
+ * Get the implemented file replacement types in
+ *
+ * @return array
+ * @static
+ */
+ static function getProvideTypes()
+ {
+ return $GLOBALS['_PEAR_Common_provide_types'];
+ }
+
+ // }}}
+ // {{{ getScriptPhases()
+
+ /**
+ * Get the implemented file replacement types in
+ *
+ * @return array
+ * @static
+ */
+ static function getScriptPhases()
+ {
+ return $GLOBALS['_PEAR_Common_script_phases'];
+ }
+
+ // }}}
+ // {{{ validPackageName()
+
+ /**
+ * Test whether a string contains a valid package name.
+ *
+ * @param string $name the package name to test
+ *
+ * @return bool
+ *
+ * @access public
+ */
+ function validPackageName($name)
+ {
+ return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name);
+ }
+
+
+ // }}}
+ // {{{ validPackageVersion()
+
+ /**
+ * Test whether a string contains a valid package version.
+ *
+ * @param string $ver the package version to test
+ *
+ * @return bool
+ *
+ * @access public
+ */
+ function validPackageVersion($ver)
+ {
+ return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
+ }
+
+
+ // }}}
+
+ // {{{ downloadHttp()
+
+ /**
+ * Download a file through HTTP. Considers suggested file name in
+ * Content-disposition: header and can run a callback function for
+ * different events. The callback will be called with two
+ * parameters: the callback type, and parameters. The implemented
+ * callback types are:
+ *
+ * 'setup' called at the very beginning, parameter is a UI object
+ * that should be used for all output
+ * 'message' the parameter is a string with an informational message
+ * 'saveas' may be used to save with a different file name, the
+ * parameter is the filename that is about to be used.
+ * If a 'saveas' callback returns a non-empty string,
+ * that file name will be used as the filename instead.
+ * Note that $save_dir will not be affected by this, only
+ * the basename of the file.
+ * 'start' download is starting, parameter is number of bytes
+ * that are expected, or -1 if unknown
+ * 'bytesread' parameter is the number of bytes read so far
+ * 'done' download is complete, parameter is the total number
+ * of bytes read
+ * 'connfailed' if the TCP connection fails, this callback is called
+ * with array(host,port,errno,errmsg)
+ * 'writefailed' if writing to disk fails, this callback is called
+ * with array(destfile,errmsg)
+ *
+ * If an HTTP proxy has been configured (http_proxy PEAR_Config
+ * setting), the proxy will be used.
+ *
+ * @param string $url the URL to download
+ * @param object $ui PEAR_Frontend_* instance
+ * @param object $config PEAR_Config instance
+ * @param string $save_dir (optional) directory to save file in
+ * @param mixed $callback (optional) function/method to call for status
+ * updates
+ *
+ * @return string Returns the full path of the downloaded file or a PEAR
+ * error on failure. If the error is caused by
+ * socket-related errors, the error object will
+ * have the fsockopen error code available through
+ * getCode().
+ *
+ * @access public
+ * @deprecated in favor of PEAR_Downloader::downloadHttp()
+ */
+ function downloadHttp($url, &$ui, $save_dir = '.', $callback = null)
+ {
+ if (!class_exists('PEAR_Downloader')) {
+ require_once 'PEAR/Downloader.php';
+ }
+ return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback);
+ }
+
+ // }}}
+
+ /**
+ * @param string $path relative or absolute include path
+ * @return boolean
+ * @static
+ */
+ static function isIncludeable($path)
+ {
+ if (file_exists($path) && is_readable($path)) {
+ return true;
+ }
+ $ipath = explode(PATH_SEPARATOR, ini_get('include_path'));
+ foreach ($ipath as $include) {
+ $test = realpath($include . DIRECTORY_SEPARATOR . $path);
+ if (file_exists($test) && is_readable($test)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+require_once 'PEAR/Config.php';
+require_once 'PEAR/PackageFile.php';
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Config.php b/vendor/library/Excel/phpxls/PEAR/Config.php
new file mode 100644
index 0000000..90c1c48
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Config.php
@@ -0,0 +1,2163 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Config.php,v 1.146 2008/05/14 04:16:08 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * Required for error handling
+ */
+require_once 'PEAR.php';
+require_once 'PEAR/Registry.php';
+require_once 'PEAR/Installer/Role.php';
+require_once 'System.php';
+require_once 'PEAR/Remote.php';
+
+/**
+ * Last created PEAR_Config instance.
+ * @var object
+ */
+$GLOBALS['_PEAR_Config_instance'] = null;
+if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) {
+ $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear';
+} else {
+ $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR;
+}
+
+// Below we define constants with default values for all configuration
+// parameters except username/password. All of them can have their
+// defaults set through environment variables. The reason we use the
+// PHP_ prefix is for some security, PHP protects environment
+// variables starting with PHP_*.
+
+// default channel and preferred mirror is based on whether we are invoked through
+// the "pear" or the "pecl" command
+
+if (!defined('PEAR_RUNTYPE') || PEAR_RUNTYPE == 'pear') {
+ define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net');
+} else {
+ define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net');
+}
+
+if (getenv('PHP_PEAR_SYSCONF_DIR')) {
+ define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR'));
+} elseif (getenv('SystemRoot')) {
+ define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot'));
+} else {
+ define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR);
+}
+
+// Default for master_server
+if (getenv('PHP_PEAR_MASTER_SERVER')) {
+ define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net');
+}
+
+// Default for http_proxy
+if (getenv('PHP_PEAR_HTTP_PROXY')) {
+ define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY'));
+} elseif (getenv('http_proxy')) {
+ define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', '');
+}
+
+// Default for php_dir
+if (getenv('PHP_PEAR_INSTALL_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR'));
+} else {
+ if (file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) {
+ define('PEAR_CONFIG_DEFAULT_PHP_DIR',
+ $PEAR_INSTALL_DIR);
+ } else {
+ define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
+ }
+}
+
+// Default for ext_dir
+if (getenv('PHP_PEAR_EXTENSION_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR'));
+} else {
+ if (ini_get('extension_dir')) {
+ define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir'));
+ } elseif (defined('PEAR_EXTENSION_DIR') &&
+ file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) {
+ define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR);
+ } elseif (defined('PHP_EXTENSION_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR);
+ } else {
+ define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.');
+ }
+}
+
+// Default for doc_dir
+if (getenv('PHP_PEAR_DOC_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_DOC_DIR',
+ $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs');
+}
+
+// Default for bin_dir
+if (getenv('PHP_PEAR_BIN_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR);
+}
+
+// Default for data_dir
+if (getenv('PHP_PEAR_DATA_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_DATA_DIR',
+ $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data');
+}
+
+// Default for cfg_dir
+if (getenv('PHP_PEAR_CFG_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_CFG_DIR',
+ $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg');
+}
+
+// Default for www_dir
+if (getenv('PHP_PEAR_WWW_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_WWW_DIR',
+ $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www');
+}
+
+// Default for test_dir
+if (getenv('PHP_PEAR_TEST_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_TEST_DIR',
+ $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests');
+}
+
+// Default for temp_dir
+if (getenv('PHP_PEAR_TEMP_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_TEMP_DIR',
+ System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
+ DIRECTORY_SEPARATOR . 'temp');
+}
+
+// Default for cache_dir
+if (getenv('PHP_PEAR_CACHE_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_CACHE_DIR',
+ System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
+ DIRECTORY_SEPARATOR . 'cache');
+}
+
+// Default for download_dir
+if (getenv('PHP_PEAR_DOWNLOAD_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR',
+ System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
+ DIRECTORY_SEPARATOR . 'download');
+}
+
+// Default for php_bin
+if (getenv('PHP_PEAR_PHP_BIN')) {
+ define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR.
+ DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : ''));
+}
+
+// Default for verbose
+if (getenv('PHP_PEAR_VERBOSE')) {
+ define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_VERBOSE', 1);
+}
+
+// Default for preferred_state
+if (getenv('PHP_PEAR_PREFERRED_STATE')) {
+ define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable');
+}
+
+// Default for umask
+if (getenv('PHP_PEAR_UMASK')) {
+ define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask()));
+}
+
+// Default for cache_ttl
+if (getenv('PHP_PEAR_CACHE_TTL')) {
+ define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600);
+}
+
+// Default for sig_type
+if (getenv('PHP_PEAR_SIG_TYPE')) {
+ define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg');
+}
+
+// Default for sig_bin
+if (getenv('PHP_PEAR_SIG_BIN')) {
+ define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_SIG_BIN',
+ System::which(
+ 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg'));
+}
+
+// Default for sig_keydir
+if (getenv('PHP_PEAR_SIG_KEYDIR')) {
+ define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR',
+ PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys');
+}
+
+/**
+ * This is a class for storing configuration data, keeping track of
+ * which are system-defined, user-defined or defaulted.
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Config extends PEAR
+{
+ // {{{ properties
+
+ /**
+ * Array of config files used.
+ *
+ * @var array layer => config file
+ */
+ var $files = array(
+ 'system' => '',
+ 'user' => '',
+ );
+
+ var $layers = array();
+
+ /**
+ * Configuration data, two-dimensional array where the first
+ * dimension is the config layer ('user', 'system' and 'default'),
+ * and the second dimension is keyname => value.
+ *
+ * The order in the first dimension is important! Earlier
+ * layers will shadow later ones when a config value is
+ * requested (if a 'user' value exists, it will be returned first,
+ * then 'system' and finally 'default').
+ *
+ * @var array layer => array(keyname => value, ...)
+ */
+ var $configuration = array(
+ 'user' => array(),
+ 'system' => array(),
+ 'default' => array(),
+ );
+
+ /**
+ * Configuration values that can be set for a channel
+ *
+ * All other configuration values can only have a global value
+ * @var array
+ * @access private
+ */
+ var $_channelConfigInfo = array(
+ 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir',
+ 'test_dir', 'www_dir', 'php_bin', 'username', 'password', 'verbose',
+ 'preferred_state', 'umask', 'preferred_mirror', 'php_ini'
+ );
+
+ /**
+ * Channels that can be accessed
+ * @see setChannels()
+ * @var array
+ * @access private
+ */
+ var $_channels = array('pear.php.net', 'pecl.php.net', '__uri');
+
+ /**
+ * This variable is used to control the directory values returned
+ * @see setInstallRoot();
+ * @var string|false
+ * @access private
+ */
+ var $_installRoot = false;
+
+ /**
+ * If requested, this will always refer to the registry
+ * contained in php_dir
+ * @var PEAR_Registry
+ */
+ var $_registry = array();
+
+ /**
+ * @var array
+ * @access private
+ */
+ var $_regInitialized = array();
+
+ /**
+ * @var bool
+ * @access private
+ */
+ var $_noRegistry = false;
+
+ /**
+ * amount of errors found while parsing config
+ * @var integer
+ * @access private
+ */
+ var $_errorsFound = 0;
+ var $_lastError = null;
+
+ /**
+ * Information about the configuration data. Stores the type,
+ * default value and a documentation string for each configuration
+ * value.
+ *
+ * @var array layer => array(infotype => value, ...)
+ */
+ var $configuration_info = array(
+ // Channels/Internet Access
+ 'default_channel' => array(
+ 'type' => 'string',
+ 'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
+ 'doc' => 'the default channel to use for all non explicit commands',
+ 'prompt' => 'Default Channel',
+ 'group' => 'Internet Access',
+ ),
+ 'preferred_mirror' => array(
+ 'type' => 'string',
+ 'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
+ 'doc' => 'the default server or mirror to use for channel actions',
+ 'prompt' => 'Default Channel Mirror',
+ 'group' => 'Internet Access',
+ ),
+ 'remote_config' => array(
+ 'type' => 'password',
+ 'default' => '',
+ 'doc' => 'ftp url of remote configuration file to use for synchronized install',
+ 'prompt' => 'Remote Configuration File',
+ 'group' => 'Internet Access',
+ ),
+ 'auto_discover' => array(
+ 'type' => 'integer',
+ 'default' => 0,
+ 'doc' => 'whether to automatically discover new channels',
+ 'prompt' => 'Auto-discover new Channels',
+ 'group' => 'Internet Access',
+ ),
+ // Internet Access
+ 'master_server' => array(
+ 'type' => 'string',
+ 'default' => 'pear.php.net',
+ 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]',
+ 'prompt' => 'PEAR server [DEPRECATED]',
+ 'group' => 'Internet Access',
+ ),
+ 'http_proxy' => array(
+ 'type' => 'string',
+ 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY,
+ 'doc' => 'HTTP proxy (host:port) to use when downloading packages',
+ 'prompt' => 'HTTP Proxy Server Address',
+ 'group' => 'Internet Access',
+ ),
+ // File Locations
+ 'php_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR,
+ 'doc' => 'directory where .php files are installed',
+ 'prompt' => 'PEAR directory',
+ 'group' => 'File Locations',
+ ),
+ 'ext_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR,
+ 'doc' => 'directory where loadable extensions are installed',
+ 'prompt' => 'PHP extension directory',
+ 'group' => 'File Locations',
+ ),
+ 'doc_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR,
+ 'doc' => 'directory where documentation is installed',
+ 'prompt' => 'PEAR documentation directory',
+ 'group' => 'File Locations',
+ ),
+ 'bin_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR,
+ 'doc' => 'directory where executables are installed',
+ 'prompt' => 'PEAR executables directory',
+ 'group' => 'File Locations',
+ ),
+ 'data_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR,
+ 'doc' => 'directory where data files are installed',
+ 'prompt' => 'PEAR data directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'cfg_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR,
+ 'doc' => 'directory where modifiable configuration files are installed',
+ 'prompt' => 'PEAR configuration file directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'www_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR,
+ 'doc' => 'directory where www frontend files (html/js) are installed',
+ 'prompt' => 'PEAR www files directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'test_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR,
+ 'doc' => 'directory where regression tests are installed',
+ 'prompt' => 'PEAR test directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'cache_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR,
+ 'doc' => 'directory which is used for XMLRPC cache',
+ 'prompt' => 'PEAR Installer cache directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'temp_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR,
+ 'doc' => 'directory which is used for all temp files',
+ 'prompt' => 'PEAR Installer temp directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'download_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR,
+ 'doc' => 'directory which is used for all downloaded files',
+ 'prompt' => 'PEAR Installer download directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'php_bin' => array(
+ 'type' => 'file',
+ 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN,
+ 'doc' => 'PHP CLI/CGI binary for executing scripts',
+ 'prompt' => 'PHP CLI/CGI binary',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'php_ini' => array(
+ 'type' => 'file',
+ 'default' => '',
+ 'doc' => 'location of php.ini in which to enable PECL extensions on install',
+ 'prompt' => 'php.ini location',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ // Maintainers
+ 'username' => array(
+ 'type' => 'string',
+ 'default' => '',
+ 'doc' => '(maintainers) your PEAR account name',
+ 'prompt' => 'PEAR username (for maintainers)',
+ 'group' => 'Maintainers',
+ ),
+ 'password' => array(
+ 'type' => 'password',
+ 'default' => '',
+ 'doc' => '(maintainers) your PEAR account password',
+ 'prompt' => 'PEAR password (for maintainers)',
+ 'group' => 'Maintainers',
+ ),
+ // Advanced
+ 'verbose' => array(
+ 'type' => 'integer',
+ 'default' => PEAR_CONFIG_DEFAULT_VERBOSE,
+ 'doc' => 'verbosity level
+0: really quiet
+1: somewhat quiet
+2: verbose
+3: debug',
+ 'prompt' => 'Debug Log Level',
+ 'group' => 'Advanced',
+ ),
+ 'preferred_state' => array(
+ 'type' => 'set',
+ 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE,
+ 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified',
+ 'valid_set' => array(
+ 'stable', 'beta', 'alpha', 'devel', 'snapshot'),
+ 'prompt' => 'Preferred Package State',
+ 'group' => 'Advanced',
+ ),
+ 'umask' => array(
+ 'type' => 'mask',
+ 'default' => PEAR_CONFIG_DEFAULT_UMASK,
+ 'doc' => 'umask used when creating files (Unix-like systems only)',
+ 'prompt' => 'Unix file mask',
+ 'group' => 'Advanced',
+ ),
+ 'cache_ttl' => array(
+ 'type' => 'integer',
+ 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL,
+ 'doc' => 'amount of secs where the local cache is used and not updated',
+ 'prompt' => 'Cache TimeToLive',
+ 'group' => 'Advanced',
+ ),
+ 'sig_type' => array(
+ 'type' => 'set',
+ 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE,
+ 'doc' => 'which package signature mechanism to use',
+ 'valid_set' => array('gpg'),
+ 'prompt' => 'Package Signature Type',
+ 'group' => 'Maintainers',
+ ),
+ 'sig_bin' => array(
+ 'type' => 'string',
+ 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN,
+ 'doc' => 'which package signature mechanism to use',
+ 'prompt' => 'Signature Handling Program',
+ 'group' => 'Maintainers',
+ ),
+ 'sig_keyid' => array(
+ 'type' => 'string',
+ 'default' => '',
+ 'doc' => 'which key to use for signing with',
+ 'prompt' => 'Signature Key Id',
+ 'group' => 'Maintainers',
+ ),
+ 'sig_keydir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR,
+ 'doc' => 'directory where signature keys are located',
+ 'prompt' => 'Signature Key Directory',
+ 'group' => 'Maintainers',
+ ),
+ // __channels is reserved - used for channel-specific configuration
+ );
+
+ // }}}
+
+ // {{{ PEAR_Config([file], [defaults_file])
+
+ /**
+ * Constructor.
+ *
+ * @param string file to read user-defined options from
+ * @param string file to read system-wide defaults from
+ * @param bool determines whether a registry object "follows"
+ * the value of php_dir (is automatically created
+ * and moved when php_dir is changed)
+ * @param bool if true, fails if configuration files cannot be loaded
+ *
+ * @access public
+ *
+ * @see PEAR_Config::singleton
+ */
+ function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false,
+ $strict = true)
+ {
+ $this->PEAR();
+ PEAR_Installer_Role::initializeConfig($this);
+ $sl = DIRECTORY_SEPARATOR;
+ if (empty($user_file)) {
+ if (OS_WINDOWS) {
+ $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini';
+ } else {
+ $user_file = getenv('HOME') . $sl . '.pearrc';
+ }
+ }
+ if (empty($system_file)) {
+ if (OS_WINDOWS) {
+ $system_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini';
+ } else {
+ $system_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf';
+ }
+ }
+
+ $this->layers = array_keys($this->configuration);
+ $this->files['user'] = $user_file;
+ $this->files['system'] = $system_file;
+ if ($user_file && file_exists($user_file)) {
+ $this->pushErrorHandling(PEAR_ERROR_RETURN);
+ $this->readConfigFile($user_file, 'user', $strict);
+ $this->popErrorHandling();
+ if ($this->_errorsFound > 0) {
+ return;
+ }
+ }
+
+ if ($system_file && file_exists($system_file)) {
+ $this->mergeConfigFile($system_file, false, 'system', $strict);
+ if ($this->_errorsFound > 0) {
+ return;
+ }
+
+ }
+
+ if (!$ftp_file) {
+ $ftp_file = $this->get('remote_config');
+ }
+
+ if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) {
+ $this->readFTPConfigFile($ftp_file);
+ }
+
+ foreach ($this->configuration_info as $key => $info) {
+ $this->configuration['default'][$key] = $info['default'];
+ }
+
+ $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']);
+ $this->_registry['default']->setConfig($this, false);
+ $this->_regInitialized['default'] = false;
+ //$GLOBALS['_PEAR_Config_instance'] = &$this;
+ }
+
+ // }}}
+ /**
+ * Return the default locations of user and system configuration files
+ * @static
+ */
+ static function getDefaultConfigFiles()
+ {
+ $sl = DIRECTORY_SEPARATOR;
+ if (OS_WINDOWS) {
+ return array(
+ 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini',
+ 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini'
+ );
+ } else {
+ return array(
+ 'user' => getenv('HOME') . $sl . '.pearrc',
+ 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf'
+ );
+ }
+ }
+ // {{{ singleton([file], [defaults_file])
+
+ /**
+ * Static singleton method. If you want to keep only one instance
+ * of this class in use, this method will give you a reference to
+ * the last created PEAR_Config object if one exists, or create a
+ * new object.
+ *
+ * @param string (optional) file to read user-defined options from
+ * @param string (optional) file to read system-wide defaults from
+ *
+ * @return object an existing or new PEAR_Config instance
+ *
+ * @access public
+ *
+ * @see PEAR_Config::PEAR_Config
+ */
+ function &singleton($user_file = '', $system_file = '', $strict = true)
+ {
+ if (is_object($GLOBALS['_PEAR_Config_instance'])) {
+ return $GLOBALS['_PEAR_Config_instance'];
+ }
+
+ $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict);
+ if ($t_conf->_errorsFound > 0) {
+ return $t_conf->lastError;
+ }
+
+ $GLOBALS['_PEAR_Config_instance'] = &$t_conf;
+ return $GLOBALS['_PEAR_Config_instance'];
+ }
+
+ // }}}
+ // {{{ validConfiguration()
+
+ /**
+ * Determine whether any configuration files have been detected, and whether a
+ * registry object can be retrieved from this configuration.
+ * @return bool
+ * @since PEAR 1.4.0a1
+ */
+ function validConfiguration()
+ {
+ if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) {
+ return true;
+ }
+ return false;
+ }
+
+ // }}}
+ // {{{ readConfigFile([file], [layer])
+
+ /**
+ * Reads configuration data from a file. All existing values in
+ * the config layer are discarded and replaced with data from the
+ * file.
+ * @param string file to read from, if NULL or not specified, the
+ * last-used file for the same layer (second param) is used
+ * @param string config layer to insert data into ('user' or 'system')
+ * @return bool TRUE on success or a PEAR error on failure
+ */
+ function readConfigFile($file = null, $layer = 'user', $strict = true)
+ {
+ if (empty($this->files[$layer])) {
+ return $this->raiseError("unknown config layer `$layer'");
+ }
+
+ if ($file === null) {
+ $file = $this->files[$layer];
+ }
+
+ $data = $this->_readConfigDataFrom($file);
+
+ if (PEAR::isError($data)) {
+ if ($strict) {
+ $this->_errorsFound++;
+ $this->lastError = $data;
+
+ return $data;
+ } else {
+ return true;
+ }
+ } else {
+ $this->files[$layer] = $file;
+ }
+
+ $this->_decodeInput($data);
+ $this->configuration[$layer] = $data;
+ $this->_setupChannels();
+ if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
+ $this->_registry[$layer] = &new PEAR_Registry($phpdir);
+ $this->_registry[$layer]->setConfig($this, false);
+ $this->_regInitialized[$layer] = false;
+ } else {
+ unset($this->_registry[$layer]);
+ }
+ return true;
+ }
+
+ // }}}
+
+ /**
+ * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini
+ * @return true|PEAR_Error
+ */
+ function readFTPConfigFile($path)
+ {
+ do { // poor man's try
+ if (!class_exists('PEAR_FTP')) {
+ if (!class_exists('PEAR_Common')) {
+ require_once 'PEAR/Common.php';
+ }
+ if (PEAR_Common::isIncludeable('PEAR/FTP.php')) {
+ require_once 'PEAR/FTP.php';
+ }
+ }
+ if (class_exists('PEAR_FTP')) {
+ $this->_ftp = &new PEAR_FTP;
+ $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN);
+ $e = $this->_ftp->init($path);
+ if (PEAR::isError($e)) {
+ $this->_ftp->popErrorHandling();
+ return $e;
+ }
+ $tmp = System::mktemp('-d');
+ PEAR_Common::addTempFile($tmp);
+ $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR .
+ 'pear.ini', false, FTP_BINARY);
+ if (PEAR::isError($e)) {
+ $this->_ftp->popErrorHandling();
+ return $e;
+ }
+ PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini');
+ $this->_ftp->disconnect();
+ $this->_ftp->popErrorHandling();
+ $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini';
+ $e = $this->readConfigFile(null, 'ftp');
+ if (PEAR::isError($e)) {
+ return $e;
+ }
+ $fail = array();
+ foreach ($this->configuration_info as $key => $val) {
+ if (in_array($this->getGroup($key),
+ array('File Locations', 'File Locations (Advanced)')) &&
+ $this->getType($key) == 'directory') {
+ // any directory configs must be set for this to work
+ if (!isset($this->configuration['ftp'][$key])) {
+ $fail[] = $key;
+ }
+ }
+ }
+ if (count($fail)) {
+ $fail = '"' . implode('", "', $fail) . '"';
+ unset($this->files['ftp']);
+ unset($this->configuration['ftp']);
+ return PEAR::raiseError('ERROR: Ftp configuration file must set all ' .
+ 'directory configuration variables. These variables were not set: ' .
+ $fail);
+ } else {
+ return true;
+ }
+ } else {
+ return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config');
+ }
+ } while (false); // poor man's catch
+ unset($this->files['ftp']);
+ return PEAR::raiseError('no remote host specified');
+ }
+
+ // {{{ _setupChannels()
+
+ /**
+ * Reads the existing configurations and creates the _channels array from it
+ */
+ function _setupChannels()
+ {
+ $set = array_flip(array_values($this->_channels));
+ foreach ($this->configuration as $layer => $data) {
+ $i = 1000;
+ if (isset($data['__channels']) && is_array($data['__channels'])) {
+ foreach ($data['__channels'] as $channel => $info) {
+ $set[$channel] = $i++;
+ }
+ }
+ }
+ $this->_channels = array_values(array_flip($set));
+ $this->setChannels($this->_channels);
+ }
+
+ // }}}
+ // {{{ deleteChannel(channel)
+
+ function deleteChannel($channel)
+ {
+ foreach ($this->configuration as $layer => $data) {
+ if (isset($data['__channels'])) {
+ if (isset($data['__channels'][strtolower($channel)])) {
+ unset($this->configuration[$layer]['__channels'][strtolower($channel)]);
+ }
+ }
+ }
+ $this->_channels = array_flip($this->_channels);
+ unset($this->_channels[strtolower($channel)]);
+ $this->_channels = array_flip($this->_channels);
+ }
+
+ // }}}
+ // {{{ mergeConfigFile(file, [override], [layer])
+
+ /**
+ * Merges data into a config layer from a file. Does the same
+ * thing as readConfigFile, except it does not replace all
+ * existing values in the config layer.
+ * @param string file to read from
+ * @param bool whether to overwrite existing data (default TRUE)
+ * @param string config layer to insert data into ('user' or 'system')
+ * @param string if true, errors are returned if file opening fails
+ * @return bool TRUE on success or a PEAR error on failure
+ */
+ function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true)
+ {
+ if (empty($this->files[$layer])) {
+ return $this->raiseError("unknown config layer `$layer'");
+ }
+ if ($file === null) {
+ $file = $this->files[$layer];
+ }
+ $data = $this->_readConfigDataFrom($file);
+ if (PEAR::isError($data)) {
+ if ($strict) {
+ $this->_errorsFound++;
+ $this->lastError = $data;
+
+ return $data;
+ } else {
+ return true;
+ }
+ }
+ $this->_decodeInput($data);
+ if ($override) {
+ $this->configuration[$layer] =
+ PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data);
+ } else {
+ $this->configuration[$layer] =
+ PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]);
+ }
+ $this->_setupChannels();
+ if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
+ $this->_registry[$layer] = &new PEAR_Registry($phpdir);
+ $this->_registry[$layer]->setConfig($this, false);
+ $this->_regInitialized[$layer] = false;
+ } else {
+ unset($this->_registry[$layer]);
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ arrayMergeRecursive($arr2, $arr1)
+ /**
+ * @param array
+ * @param array
+ * @return array
+ * @static
+ */
+ static function arrayMergeRecursive($arr2, $arr1)
+ {
+ $ret = array();
+ foreach ($arr2 as $key => $data) {
+ if (!isset($arr1[$key])) {
+ $ret[$key] = $data;
+ unset($arr1[$key]);
+ continue;
+ }
+ if (is_array($data)) {
+ if (!is_array($arr1[$key])) {
+ $ret[$key] = $arr1[$key];
+ unset($arr1[$key]);
+ continue;
+ }
+ $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]);
+ unset($arr1[$key]);
+ }
+ }
+ return array_merge($ret, $arr1);
+ }
+
+ // }}}
+ // {{{ writeConfigFile([file], [layer])
+
+ /**
+ * Writes data into a config layer from a file.
+ *
+ * @param string|null file to read from, or null for default
+ * @param string config layer to insert data into ('user' or
+ * 'system')
+ * @param string|null data to write to config file or null for internal data [DEPRECATED]
+ * @return bool TRUE on success or a PEAR error on failure
+ */
+ function writeConfigFile($file = null, $layer = 'user', $data = null)
+ {
+ $this->_lazyChannelSetup($layer);
+ if ($layer == 'both' || $layer == 'all') {
+ foreach ($this->files as $type => $file) {
+ $err = $this->writeConfigFile($file, $type, $data);
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+ }
+ return true;
+ }
+ if (empty($this->files[$layer])) {
+ return $this->raiseError("unknown config file type `$layer'");
+ }
+ if ($file === null) {
+ $file = $this->files[$layer];
+ }
+ $data = ($data === null) ? $this->configuration[$layer] : $data;
+ $this->_encodeOutput($data);
+ $opt = array('-p', dirname($file));
+ if (!@System::mkDir($opt)) {
+ return $this->raiseError("could not create directory: " . dirname($file));
+ }
+ if (file_exists($file) && is_file($file) && !is_writeable($file)) {
+ return $this->raiseError("no write access to $file!");
+ }
+ $fp = @fopen($file, "w");
+ if (!$fp) {
+ return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)");
+ }
+ $contents = "#PEAR_Config 0.9\n" . serialize($data);
+ if (!@fwrite($fp, $contents)) {
+ return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)");
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ _readConfigDataFrom(file)
+
+ /**
+ * Reads configuration data from a file and returns the parsed data
+ * in an array.
+ *
+ * @param string file to read from
+ *
+ * @return array configuration data or a PEAR error on failure
+ *
+ * @access private
+ */
+ function _readConfigDataFrom($file)
+ {
+ $fp = false;
+ if (file_exists($file)) {
+ $fp = @fopen($file, "r");
+ }
+ if (!$fp) {
+ return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed");
+ }
+ $size = filesize($file);
+ $rt = get_magic_quotes_runtime();
+ set_magic_quotes_runtime(0);
+ fclose($fp);
+ $contents = file_get_contents($file);
+ if (empty($contents)) {
+ return $this->raiseError('Configuration file "' . $file . '" is empty');
+ }
+
+ set_magic_quotes_runtime($rt);
+
+ $version = false;
+ if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) {
+ $version = $matches[1];
+ $contents = substr($contents, strlen($matches[0]));
+ } else {
+ // Museum config file
+ if (substr($contents,0,2) == 'a:') {
+ $version = '0.1';
+ }
+ }
+ if ($version && version_compare("$version", '1', '<')) {
+
+ // no '@', it is possible that unserialize
+ // raises a notice but it seems to block IO to
+ // STDOUT if a '@' is used and a notice is raise
+ $data = unserialize($contents);
+
+ if (!is_array($data) && !$data) {
+ if ($contents == serialize(false)) {
+ $data = array();
+ } else {
+ $err = $this->raiseError("PEAR_Config: bad data in $file");
+ return $err;
+ }
+ }
+ if (!is_array($data)) {
+ if (strlen(trim($contents)) > 0) {
+ $error = "PEAR_Config: bad data in $file";
+ $err = $this->raiseError($error);
+ return $err;
+ } else {
+ $data = array();
+ }
+ }
+ // add parsing of newer formats here...
+ } else {
+ $err = $this->raiseError("$file: unknown version `$version'");
+ return $err;
+ }
+ return $data;
+ }
+
+ // }}}
+ // {{{ getConfFile(layer)
+ /**
+ * Gets the file used for storing the config for a layer
+ *
+ * @param string $layer 'user' or 'system'
+ */
+
+ function getConfFile($layer)
+ {
+ return $this->files[$layer];
+ }
+
+ // }}}
+
+ /**
+ * @param string Configuration class name, used for detecting duplicate calls
+ * @param array information on a role as parsed from its xml file
+ * @return true|PEAR_Error
+ * @access private
+ */
+ function _addConfigVars($class, $vars)
+ {
+ static $called = array();
+ if (isset($called[$class])) {
+ return;
+ }
+ $called[$class] = 1;
+ if (count($vars) > 3) {
+ return $this->raiseError('Roles can only define 3 new config variables or less');
+ }
+ foreach ($vars as $name => $var) {
+ if (!is_array($var)) {
+ return $this->raiseError('Configuration information must be an array');
+ }
+ if (!isset($var['type'])) {
+ return $this->raiseError('Configuration information must contain a type');
+ } else {
+ if (!in_array($var['type'],
+ array('string', 'mask', 'password', 'directory', 'file', 'set'))) {
+ return $this->raiseError(
+ 'Configuration type must be one of directory, file, string, ' .
+ 'mask, set, or password');
+ }
+ }
+ if (!isset($var['default'])) {
+ return $this->raiseError(
+ 'Configuration information must contain a default value ("default" index)');
+ } else {
+ if (is_array($var['default'])) {
+ $real_default = '';
+ foreach ($var['default'] as $config_var => $val) {
+ if (strpos($config_var, 'text') === 0) {
+ $real_default .= $val;
+ } elseif (strpos($config_var, 'constant') === 0) {
+ if (defined($val)) {
+ $real_default .= constant($val);
+ } else {
+ return $this->raiseError(
+ 'Unknown constant "' . $val . '" requested in ' .
+ 'default value for configuration variable "' .
+ $name . '"');
+ }
+ } elseif (isset($this->configuration_info[$config_var])) {
+ $real_default .=
+ $this->configuration_info[$config_var]['default'];
+ } else {
+ return $this->raiseError(
+ 'Unknown request for "' . $config_var . '" value in ' .
+ 'default value for configuration variable "' .
+ $name . '"');
+ }
+ }
+ $var['default'] = $real_default;
+ }
+ if ($var['type'] == 'integer') {
+ $var['default'] = (integer) $var['default'];
+ }
+ }
+ if (!isset($var['doc'])) {
+ return $this->raiseError(
+ 'Configuration information must contain a summary ("doc" index)');
+ }
+ if (!isset($var['prompt'])) {
+ return $this->raiseError(
+ 'Configuration information must contain a simple prompt ("prompt" index)');
+ }
+ if (!isset($var['group'])) {
+ return $this->raiseError(
+ 'Configuration information must contain a simple group ("group" index)');
+ }
+ if (isset($this->configuration_info[$name])) {
+ return $this->raiseError('Configuration variable "' . $name .
+ '" already exists');
+ }
+ $this->configuration_info[$name] = $var;
+ // fix bug #7351: setting custom config variable in a channel fails
+ $this->_channelConfigInfo[] = $name;
+ }
+ return true;
+ }
+
+ // {{{ _encodeOutput(&data)
+
+ /**
+ * Encodes/scrambles configuration data before writing to files.
+ * Currently, 'password' values will be base64-encoded as to avoid
+ * that people spot cleartext passwords by accident.
+ *
+ * @param array (reference) array to encode values in
+ *
+ * @return bool TRUE on success
+ *
+ * @access private
+ */
+ function _encodeOutput(&$data)
+ {
+ foreach ($data as $key => $value) {
+ if ($key == '__channels') {
+ foreach ($data['__channels'] as $channel => $blah) {
+ $this->_encodeOutput($data['__channels'][$channel]);
+ }
+ }
+ if (!isset($this->configuration_info[$key])) {
+ continue;
+ }
+ $type = $this->configuration_info[$key]['type'];
+ switch ($type) {
+ // we base64-encode passwords so they are at least
+ // not shown in plain by accident
+ case 'password': {
+ $data[$key] = base64_encode($data[$key]);
+ break;
+ }
+ case 'mask': {
+ $data[$key] = octdec($data[$key]);
+ break;
+ }
+ }
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ _decodeInput(&data)
+
+ /**
+ * Decodes/unscrambles configuration data after reading from files.
+ *
+ * @param array (reference) array to encode values in
+ *
+ * @return bool TRUE on success
+ *
+ * @access private
+ *
+ * @see PEAR_Config::_encodeOutput
+ */
+ function _decodeInput(&$data)
+ {
+ if (!is_array($data)) {
+ return true;
+ }
+ foreach ($data as $key => $value) {
+ if ($key == '__channels') {
+ foreach ($data['__channels'] as $channel => $blah) {
+ $this->_decodeInput($data['__channels'][$channel]);
+ }
+ }
+ if (!isset($this->configuration_info[$key])) {
+ continue;
+ }
+ $type = $this->configuration_info[$key]['type'];
+ switch ($type) {
+ case 'password': {
+ $data[$key] = base64_decode($data[$key]);
+ break;
+ }
+ case 'mask': {
+ $data[$key] = decoct($data[$key]);
+ break;
+ }
+ }
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ getDefaultChannel([layer])
+ /**
+ * Retrieve the default channel.
+ *
+ * On startup, channels are not initialized, so if the default channel is not
+ * pear.php.net, then initialize the config.
+ * @param string registry layer
+ * @return string|false
+ */
+ function getDefaultChannel($layer = null)
+ {
+ $ret = false;
+ if ($layer === null) {
+ foreach ($this->layers as $layer) {
+ if (isset($this->configuration[$layer]['default_channel'])) {
+ $ret = $this->configuration[$layer]['default_channel'];
+ break;
+ }
+ }
+ } elseif (isset($this->configuration[$layer]['default_channel'])) {
+ $ret = $this->configuration[$layer]['default_channel'];
+ }
+ if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') {
+ $ret = 'pecl.php.net';
+ }
+ if ($ret) {
+ if ($ret != 'pear.php.net') {
+ $this->_lazyChannelSetup();
+ }
+ return $ret;
+ }
+ return PEAR_CONFIG_DEFAULT_CHANNEL;
+ }
+
+ // {{{ get(key, [layer])
+ /**
+ * Returns a configuration value, prioritizing layers as per the
+ * layers property.
+ *
+ * @param string config key
+ *
+ * @return mixed the config value, or NULL if not found
+ *
+ * @access public
+ */
+ function get($key, $layer = null, $channel = false)
+ {
+ if (!isset($this->configuration_info[$key])) {
+ return null;
+ }
+ if ($key == '__channels') {
+ return null;
+ }
+ if ($key == 'default_channel') {
+ return $this->getDefaultChannel($layer);
+ }
+ if (!$channel) {
+ $channel = $this->getDefaultChannel();
+ } elseif ($channel != 'pear.php.net') {
+ $this->_lazyChannelSetup();
+ }
+ $channel = strtolower($channel);
+
+ $test = (in_array($key, $this->_channelConfigInfo)) ?
+ $this->_getChannelValue($key, $layer, $channel) :
+ null;
+ if ($test !== null) {
+ if ($this->_installRoot) {
+ if (in_array($this->getGroup($key),
+ array('File Locations', 'File Locations (Advanced)')) &&
+ $this->getType($key) == 'directory') {
+ return $this->_prependPath($test, $this->_installRoot);
+ }
+ }
+ return $test;
+ }
+ if ($layer === null) {
+ foreach ($this->layers as $layer) {
+ if (isset($this->configuration[$layer][$key])) {
+ $test = $this->configuration[$layer][$key];
+ if ($this->_installRoot) {
+ if (in_array($this->getGroup($key),
+ array('File Locations', 'File Locations (Advanced)')) &&
+ $this->getType($key) == 'directory') {
+ return $this->_prependPath($test, $this->_installRoot);
+ }
+ }
+ if ($key == 'preferred_mirror') {
+ $reg = &$this->getRegistry();
+ if (is_object($reg)) {
+ $chan = &$reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $channel;
+ }
+ if (!$chan->getMirror($test) && $chan->getName() != $test) {
+ return $channel; // mirror does not exist
+ }
+ }
+ }
+ return $test;
+ }
+ }
+ } elseif (isset($this->configuration[$layer][$key])) {
+ $test = $this->configuration[$layer][$key];
+ if ($this->_installRoot) {
+ if (in_array($this->getGroup($key),
+ array('File Locations', 'File Locations (Advanced)')) &&
+ $this->getType($key) == 'directory') {
+ return $this->_prependPath($test, $this->_installRoot);
+ }
+ }
+ if ($key == 'preferred_mirror') {
+ $reg = &$this->getRegistry();
+ if (is_object($reg)) {
+ $chan = &$reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $channel;
+ }
+ if (!$chan->getMirror($test) && $chan->getName() != $test) {
+ return $channel; // mirror does not exist
+ }
+ }
+ }
+ return $test;
+ }
+ return null;
+ }
+
+ // }}}
+ // {{{ _getChannelValue(key, value, [layer])
+ /**
+ * Returns a channel-specific configuration value, prioritizing layers as per the
+ * layers property.
+ *
+ * @param string config key
+ *
+ * @return mixed the config value, or NULL if not found
+ *
+ * @access private
+ */
+ function _getChannelValue($key, $layer, $channel)
+ {
+ if ($key == '__channels' || $channel == 'pear.php.net') {
+ return null;
+ }
+ $ret = null;
+ if ($layer === null) {
+ foreach ($this->layers as $ilayer) {
+ if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) {
+ $ret = $this->configuration[$ilayer]['__channels'][$channel][$key];
+ break;
+ }
+ }
+ } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
+ $ret = $this->configuration[$layer]['__channels'][$channel][$key];
+ }
+ if ($key == 'preferred_mirror') {
+ if ($ret !== null) {
+ $reg = &$this->getRegistry($layer);
+ if (is_object($reg)) {
+ $chan = &$reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $channel;
+ }
+ if (!$chan->getMirror($ret) && $chan->getName() != $ret) {
+ return $channel; // mirror does not exist
+ }
+ }
+ return $ret;
+ }
+ if ($channel != $this->getDefaultChannel($layer)) {
+ return $channel; // we must use the channel name as the preferred mirror
+ // if the user has not chosen an alternate
+ } else {
+ return $this->getDefaultChannel($layer);
+ }
+ }
+ return $ret;
+ }
+
+
+ // }}}
+ // {{{ set(key, value, [layer])
+
+ /**
+ * Set a config value in a specific layer (defaults to 'user').
+ * Enforces the types defined in the configuration_info array. An
+ * integer config variable will be cast to int, and a set config
+ * variable will be validated against its legal values.
+ *
+ * @param string config key
+ * @param string config value
+ * @param string (optional) config layer
+ * @param string channel to set this value for, or null for global value
+ * @return bool TRUE on success, FALSE on failure
+ */
+ function set($key, $value, $layer = 'user', $channel = false)
+ {
+ if ($key == '__channels') {
+ return false;
+ }
+ if (!isset($this->configuration[$layer])) {
+ return false;
+ }
+ if ($key == 'default_channel') {
+ // can only set this value globally
+ $channel = 'pear.php.net';
+ if ($value != 'pear.php.net') {
+ $this->_lazyChannelSetup($layer);
+ }
+ }
+ if ($key == 'preferred_mirror') {
+ if ($channel == '__uri') {
+ return false; // can't set the __uri pseudo-channel's mirror
+ }
+ $reg = &$this->getRegistry($layer);
+ if (is_object($reg)) {
+ $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net');
+ if (PEAR::isError($chan)) {
+ return false;
+ }
+ if (!$chan->getMirror($value) && $chan->getName() != $value) {
+ return false; // mirror does not exist
+ }
+ }
+ }
+ if (!isset($this->configuration_info[$key])) {
+ return false;
+ }
+ extract($this->configuration_info[$key]);
+ switch ($type) {
+ case 'integer':
+ $value = (int)$value;
+ break;
+ case 'set': {
+ // If a valid_set is specified, require the value to
+ // be in the set. If there is no valid_set, accept
+ // any value.
+ if ($valid_set) {
+ reset($valid_set);
+ if ((key($valid_set) === 0 && !in_array($value, $valid_set)) ||
+ (key($valid_set) !== 0 && empty($valid_set[$value])))
+ {
+ return false;
+ }
+ }
+ break;
+ }
+ }
+ if (!$channel) {
+ $channel = $this->get('default_channel', null, 'pear.php.net');
+ }
+ if (!in_array($channel, $this->_channels)) {
+ $this->_lazyChannelSetup($layer);
+ $reg = &$this->getRegistry($layer);
+ if ($reg) {
+ $channel = $reg->channelName($channel);
+ }
+ if (!in_array($channel, $this->_channels)) {
+ return false;
+ }
+ }
+ if ($channel != 'pear.php.net') {
+ if (in_array($key, $this->_channelConfigInfo)) {
+ $this->configuration[$layer]['__channels'][$channel][$key] = $value;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ if ($key == 'default_channel') {
+ if (!isset($reg)) {
+ $reg = &$this->getRegistry($layer);
+ if (!$reg) {
+ $reg = &$this->getRegistry();
+ }
+ }
+ if ($reg) {
+ $value = $reg->channelName($value);
+ }
+ if (!$value) {
+ return false;
+ }
+ }
+ }
+ $this->configuration[$layer][$key] = $value;
+ if ($key == 'php_dir' && !$this->_noRegistry) {
+ if (!isset($this->_registry[$layer]) ||
+ $value != $this->_registry[$layer]->install_dir) {
+ $this->_registry[$layer] = &new PEAR_Registry($value);
+ $this->_regInitialized[$layer] = false;
+ $this->_registry[$layer]->setConfig($this, false);
+ }
+ }
+ return true;
+ }
+
+ // }}}
+ function _lazyChannelSetup($uselayer = false)
+ {
+ if ($this->_noRegistry) {
+ return;
+ }
+ $merge = false;
+ foreach ($this->_registry as $layer => $p) {
+ if ($uselayer && $uselayer != $layer) {
+ continue;
+ }
+ if (!$this->_regInitialized[$layer]) {
+ if ($layer == 'default' && isset($this->_registry['user']) ||
+ isset($this->_registry['system'])) {
+ // only use the default registry if there are no alternatives
+ continue;
+ }
+ if (!is_object($this->_registry[$layer])) {
+ if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) {
+ $this->_registry[$layer] = &new PEAR_Registry($phpdir);
+ $this->_registry[$layer]->setConfig($this, false);
+ $this->_regInitialized[$layer] = false;
+ } else {
+ unset($this->_registry[$layer]);
+ return;
+ }
+ }
+ $this->setChannels($this->_registry[$layer]->listChannels(), $merge);
+ $this->_regInitialized[$layer] = true;
+ $merge = true;
+ }
+ }
+ }
+ // {{{ setChannels()
+
+ /**
+ * Set the list of channels.
+ *
+ * This should be set via a call to {@link PEAR_Registry::listChannels()}
+ * @param array
+ * @param bool
+ * @return bool success of operation
+ */
+ function setChannels($channels, $merge = false)
+ {
+ if (!is_array($channels)) {
+ return false;
+ }
+ if ($merge) {
+ $this->_channels = array_merge($this->_channels, $channels);
+ } else {
+ $this->_channels = $channels;
+ }
+ foreach ($channels as $channel) {
+ $channel = strtolower($channel);
+ if ($channel == 'pear.php.net') {
+ continue;
+ }
+ foreach ($this->layers as $layer) {
+ if (!isset($this->configuration[$layer]['__channels'])) {
+ $this->configuration[$layer]['__channels'] = array();
+ }
+ if (!isset($this->configuration[$layer]['__channels'][$channel])
+ || !is_array($this->configuration[$layer]['__channels'][$channel])) {
+ $this->configuration[$layer]['__channels'][$channel] = array();
+ }
+ }
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ getType(key)
+
+ /**
+ * Get the type of a config value.
+ *
+ * @param string config key
+ *
+ * @return string type, one of "string", "integer", "file",
+ * "directory", "set" or "password".
+ *
+ * @access public
+ *
+ */
+ function getType($key)
+ {
+ if (isset($this->configuration_info[$key])) {
+ return $this->configuration_info[$key]['type'];
+ }
+ return false;
+ }
+
+ // }}}
+ // {{{ getDocs(key)
+
+ /**
+ * Get the documentation for a config value.
+ *
+ * @param string config key
+ *
+ * @return string documentation string
+ *
+ * @access public
+ *
+ */
+ function getDocs($key)
+ {
+ if (isset($this->configuration_info[$key])) {
+ return $this->configuration_info[$key]['doc'];
+ }
+ return false;
+ }
+ // }}}
+ // {{{ getPrompt(key)
+
+ /**
+ * Get the short documentation for a config value.
+ *
+ * @param string config key
+ *
+ * @return string short documentation string
+ *
+ * @access public
+ *
+ */
+ function getPrompt($key)
+ {
+ if (isset($this->configuration_info[$key])) {
+ return $this->configuration_info[$key]['prompt'];
+ }
+ return false;
+ }
+ // }}}
+ // {{{ getGroup(key)
+
+ /**
+ * Get the parameter group for a config key.
+ *
+ * @param string config key
+ *
+ * @return string parameter group
+ *
+ * @access public
+ *
+ */
+ function getGroup($key)
+ {
+ if (isset($this->configuration_info[$key])) {
+ return $this->configuration_info[$key]['group'];
+ }
+ return false;
+ }
+
+ // }}}
+ // {{{ getGroups()
+
+ /**
+ * Get the list of parameter groups.
+ *
+ * @return array list of parameter groups
+ *
+ * @access public
+ *
+ */
+ function getGroups()
+ {
+ $tmp = array();
+ foreach ($this->configuration_info as $key => $info) {
+ $tmp[$info['group']] = 1;
+ }
+ return array_keys($tmp);
+ }
+
+ // }}}
+ // {{{ getGroupKeys()
+
+ /**
+ * Get the list of the parameters in a group.
+ *
+ * @param string $group parameter group
+ *
+ * @return array list of parameters in $group
+ *
+ * @access public
+ *
+ */
+ function getGroupKeys($group)
+ {
+ $keys = array();
+ foreach ($this->configuration_info as $key => $info) {
+ if ($info['group'] == $group) {
+ $keys[] = $key;
+ }
+ }
+ return $keys;
+ }
+
+ // }}}
+ // {{{ getSetValues(key)
+
+ /**
+ * Get the list of allowed set values for a config value. Returns
+ * NULL for config values that are not sets.
+ *
+ * @param string config key
+ *
+ * @return array enumerated array of set values, or NULL if the
+ * config key is unknown or not a set
+ *
+ * @access public
+ *
+ */
+ function getSetValues($key)
+ {
+ if (isset($this->configuration_info[$key]) &&
+ isset($this->configuration_info[$key]['type']) &&
+ $this->configuration_info[$key]['type'] == 'set')
+ {
+ $valid_set = $this->configuration_info[$key]['valid_set'];
+ reset($valid_set);
+ if (key($valid_set) === 0) {
+ return $valid_set;
+ }
+ return array_keys($valid_set);
+ }
+ return null;
+ }
+
+ // }}}
+ // {{{ getKeys()
+
+ /**
+ * Get all the current config keys.
+ *
+ * @return array simple array of config keys
+ *
+ * @access public
+ */
+ function getKeys()
+ {
+ $keys = array();
+ foreach ($this->layers as $layer) {
+ $test = $this->configuration[$layer];
+ if (isset($test['__channels'])) {
+ foreach ($test['__channels'] as $channel => $configs) {
+ $keys = array_merge($keys, $configs);
+ }
+ }
+ unset($test['__channels']);
+ $keys = array_merge($keys, $test);
+ }
+ return array_keys($keys);
+ }
+
+ // }}}
+ // {{{ remove(key, [layer])
+
+ /**
+ * Remove the a config key from a specific config layer.
+ *
+ * @param string config key
+ *
+ * @param string (optional) config layer
+ *
+ * @return bool TRUE on success, FALSE on failure
+ *
+ * @access public
+ */
+ function remove($key, $layer = 'user')
+ {
+ $channel = $this->getDefaultChannel();
+ if ($channel !== 'pear.php.net') {
+ if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
+ unset($this->configuration[$layer]['__channels'][$channel][$key]);
+ return true;
+ }
+ }
+ if (isset($this->configuration[$layer][$key])) {
+ unset($this->configuration[$layer][$key]);
+ return true;
+ }
+ return false;
+ }
+
+ // }}}
+ // {{{ removeLayer(layer)
+
+ /**
+ * Temporarily remove an entire config layer. USE WITH CARE!
+ *
+ * @param string config key
+ *
+ * @param string (optional) config layer
+ *
+ * @return bool TRUE on success, FALSE on failure
+ *
+ * @access public
+ */
+ function removeLayer($layer)
+ {
+ if (isset($this->configuration[$layer])) {
+ $this->configuration[$layer] = array();
+ return true;
+ }
+ return false;
+ }
+
+ // }}}
+ // {{{ store([layer])
+
+ /**
+ * Stores configuration data in a layer.
+ *
+ * @param string config layer to store
+ *
+ * @return bool TRUE on success, or PEAR error on failure
+ *
+ * @access public
+ */
+ function store($layer = 'user', $data = null)
+ {
+ return $this->writeConfigFile(null, $layer, $data);
+ }
+
+ // }}}
+ // {{{ toDefault(key)
+
+ /**
+ * Unset the user-defined value of a config key, reverting the
+ * value to the system-defined one.
+ *
+ * @param string config key
+ *
+ * @return bool TRUE on success, FALSE on failure
+ *
+ * @access public
+ */
+ function toDefault($key)
+ {
+ trigger_error("PEAR_Config::toDefault() deprecated, use PEAR_Config::remove() instead", E_USER_NOTICE);
+ return $this->remove($key, 'user');
+ }
+
+ // }}}
+ // {{{ definedBy(key)
+
+ /**
+ * Tells what config layer that gets to define a key.
+ *
+ * @param string config key
+ * @param boolean return the defining channel
+ *
+ * @return string|array the config layer, or an empty string if not found.
+ *
+ * if $returnchannel, the return is an array array('layer' => layername,
+ * 'channel' => channelname), or an empty string if not found
+ *
+ * @access public
+ */
+ function definedBy($key, $returnchannel = false)
+ {
+ foreach ($this->layers as $layer) {
+ $channel = $this->getDefaultChannel();
+ if ($channel !== 'pear.php.net') {
+ if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
+ if ($returnchannel) {
+ return array('layer' => $layer, 'channel' => $channel);
+ }
+ return $layer;
+ }
+ }
+ if (isset($this->configuration[$layer][$key])) {
+ if ($returnchannel) {
+ return array('layer' => $layer, 'channel' => 'pear.php.net');
+ }
+ return $layer;
+ }
+ }
+ return '';
+ }
+
+ // }}}
+ // {{{ isDefaulted(key)
+
+ /**
+ * Tells whether a config value has a system-defined value.
+ *
+ * @param string config key
+ *
+ * @return bool
+ *
+ * @access public
+ *
+ * @deprecated
+ */
+ function isDefaulted($key)
+ {
+ trigger_error("PEAR_Config::isDefaulted() deprecated, use PEAR_Config::definedBy() instead", E_USER_NOTICE);
+ return $this->definedBy($key) == 'system';
+ }
+
+ // }}}
+ // {{{ isDefined(key)
+
+ /**
+ * Tells whether a given key exists as a config value.
+ *
+ * @param string config key
+ *
+ * @return bool whether exists in this object
+ *
+ * @access public
+ */
+ function isDefined($key)
+ {
+ foreach ($this->layers as $layer) {
+ if (isset($this->configuration[$layer][$key])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // }}}
+ // {{{ isDefinedLayer(key)
+
+ /**
+ * Tells whether a given config layer exists.
+ *
+ * @param string config layer
+ *
+ * @return bool whether exists in this object
+ *
+ * @access public
+ */
+ function isDefinedLayer($layer)
+ {
+ return isset($this->configuration[$layer]);
+ }
+
+ // }}}
+ // {{{ getLayers()
+
+ /**
+ * Returns the layers defined (except the 'default' one)
+ *
+ * @return array of the defined layers
+ */
+ function getLayers()
+ {
+ $cf = $this->configuration;
+ unset($cf['default']);
+ return array_keys($cf);
+ }
+
+ // }}}
+ // {{{ apiVersion()
+ function apiVersion()
+ {
+ return '1.1';
+ }
+ // }}}
+
+ /**
+ * @return PEAR_Registry
+ */
+ function &getRegistry($use = null)
+ {
+ if ($use === null) {
+ $layer = 'user';
+ } else {
+ $layer = $use;
+ }
+ if (isset($this->_registry[$layer])) {
+ return $this->_registry[$layer];
+ } elseif ($use === null && isset($this->_registry['system'])) {
+ return $this->_registry['system'];
+ } elseif ($use === null && isset($this->_registry['default'])) {
+ return $this->_registry['default'];
+ } elseif ($use) {
+ $a = false;
+ return $a;
+ } else {
+ // only go here if null was passed in
+ echo "CRITICAL ERROR: Registry could not be initialized from any value";
+ exit(1);
+ }
+ }
+ /**
+ * This is to allow customization like the use of installroot
+ * @param PEAR_Registry
+ * @return bool
+ */
+ function setRegistry(&$reg, $layer = 'user')
+ {
+ if ($this->_noRegistry) {
+ return false;
+ }
+ if (!in_array($layer, array('user', 'system'))) {
+ return false;
+ }
+ $this->_registry[$layer] = &$reg;
+ if (is_object($reg)) {
+ $this->_registry[$layer]->setConfig($this, false);
+ }
+ return true;
+ }
+
+ function noRegistry()
+ {
+ $this->_noRegistry = true;
+ }
+
+ /**
+ * @return PEAR_Remote
+ */
+ function &getRemote()
+ {
+ $remote = &new PEAR_Remote($this);
+ return $remote;
+ }
+
+ /**
+ * @return PEAR_REST
+ */
+ function &getREST($version, $options = array())
+ {
+ $version = str_replace('.', '', $version);
+ if (!class_exists($class = 'PEAR_REST_' . $version)) {
+ require_once 'PEAR/REST/' . $version . '.php';
+ }
+ $remote = &new $class($this, $options);
+ return $remote;
+ }
+
+ /**
+ * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a
+ * remote configuration file has been specified
+ * @return PEAR_FTP|false
+ */
+ function &getFTP()
+ {
+ if (isset($this->_ftp)) {
+ return $this->_ftp;
+ } else {
+ $a = false;
+ return $a;
+ }
+ }
+
+ // {{{ _prependPath($path, $prepend)
+
+ function _prependPath($path, $prepend)
+ {
+ if (strlen($prepend) > 0) {
+ if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
+ if (preg_match('/^[a-z]:/i', $prepend)) {
+ $prepend = substr($prepend, 2);
+ } elseif ($prepend{0} != '\\') {
+ $prepend = "\\$prepend";
+ }
+ $path = substr($path, 0, 2) . $prepend . substr($path, 2);
+ } else {
+ $path = $prepend . $path;
+ }
+ }
+ return $path;
+ }
+ // }}}
+
+ /**
+ * @param string|false installation directory to prepend to all _dir variables, or false to
+ * disable
+ */
+ function setInstallRoot($root)
+ {
+ if (substr($root, -1) == DIRECTORY_SEPARATOR) {
+ $root = substr($root, 0, -1);
+ }
+ $old = $this->_installRoot;
+ $this->_installRoot = $root;
+ if (($old != $root) && !$this->_noRegistry) {
+ foreach (array_keys($this->_registry) as $layer) {
+ if ($layer == 'ftp' || !isset($this->_registry[$layer])) {
+ continue;
+ }
+ $this->_registry[$layer] =
+ &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net'));
+ $this->_registry[$layer]->setConfig($this, false);
+ $this->_regInitialized[$layer] = false;
+ }
+ }
+ }
+}
+
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Dependency.php b/vendor/library/Excel/phpxls/PEAR/Dependency.php
new file mode 100644
index 0000000..0265f6f
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Dependency.php
@@ -0,0 +1,498 @@
+
+ * @author Stig Bakken
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Dependency.php,v 1.43 2008/01/03 20:26:34 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+require_once "PEAR.php";
+require_once "OS/Guess.php";
+
+define('PEAR_DEPENDENCY_MISSING', -1);
+define('PEAR_DEPENDENCY_CONFLICT', -2);
+define('PEAR_DEPENDENCY_UPGRADE_MINOR', -3);
+define('PEAR_DEPENDENCY_UPGRADE_MAJOR', -4);
+define('PEAR_DEPENDENCY_BAD_DEPENDENCY', -5);
+define('PEAR_DEPENDENCY_MISSING_OPTIONAL', -6);
+define('PEAR_DEPENDENCY_CONFLICT_OPTIONAL', -7);
+define('PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL', -8);
+define('PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL', -9);
+
+/**
+ * Dependency check for PEAR packages
+ *
+ * The class is based on the dependency RFC that can be found at
+ * http://cvs.php.net/cvs.php/pearweb/rfc. It requires PHP >= 4.1
+ *
+ * @author Tomas V.V.Vox
+ * @author Stig Bakken
+ */
+class PEAR_Dependency
+{
+ // {{{ constructor
+ /**
+ * Constructor
+ *
+ * @access public
+ * @param object Registry object
+ * @return void
+ */
+ function PEAR_Dependency(&$registry)
+ {
+ $this->registry = &$registry;
+ }
+
+ // }}}
+ // {{{ callCheckMethod()
+
+ /**
+ * This method maps the XML dependency definition to the
+ * corresponding one from PEAR_Dependency
+ *
+ *
+ * @access private
+ * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON']
+ */
+$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
+
+/**
+ * Global error callback (default)
+ *
+ * This is only used if set to non-false. * is the default callback for
+ * all packages, whereas specific packages may set a default callback
+ * for all instances, regardless of whether they are a singleton or not.
+ *
+ * To exclude non-singletons, only set the local callback for the singleton
+ * @see PEAR_ErrorStack::setDefaultCallback()
+ * @access private
+ * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']
+ */
+$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array(
+ '*' => false,
+);
+
+/**
+ * Global Log object (default)
+ *
+ * This is only used if set to non-false. Use to set a default log object for
+ * all stacks, regardless of instantiation order or location
+ * @see PEAR_ErrorStack::setDefaultLogger()
+ * @access private
+ * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
+ */
+$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
+
+/**
+ * Global Overriding Callback
+ *
+ * This callback will override any error callbacks that specific loggers have set.
+ * Use with EXTREME caution
+ * @see PEAR_ErrorStack::staticPushCallback()
+ * @access private
+ * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
+ */
+$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
+
+/**#@+
+ * One of four possible return values from the error Callback
+ * @see PEAR_ErrorStack::_errorCallback()
+ */
+/**
+ * If this is returned, then the error will be both pushed onto the stack
+ * and logged.
+ */
+define('PEAR_ERRORSTACK_PUSHANDLOG', 1);
+/**
+ * If this is returned, then the error will only be pushed onto the stack,
+ * and not logged.
+ */
+define('PEAR_ERRORSTACK_PUSH', 2);
+/**
+ * If this is returned, then the error will only be logged, but not pushed
+ * onto the error stack.
+ */
+define('PEAR_ERRORSTACK_LOG', 3);
+/**
+ * If this is returned, then the error is completely ignored.
+ */
+define('PEAR_ERRORSTACK_IGNORE', 4);
+/**
+ * If this is returned, then the error is logged and die() is called.
+ */
+define('PEAR_ERRORSTACK_DIE', 5);
+/**#@-*/
+
+/**
+ * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in
+ * the singleton method.
+ */
+define('PEAR_ERRORSTACK_ERR_NONCLASS', 1);
+
+/**
+ * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()}
+ * that has no __toString() method
+ */
+define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
+/**
+ * Error Stack Implementation
+ *
+ * Usage:
+ *
+ * // global error stack
+ * $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
+ * // local error stack
+ * $local_stack = new PEAR_ErrorStack('MyPackage');
+ *
+ * @author Greg Beaver
+ * @version 1.7.2
+ * @package PEAR_ErrorStack
+ * @category Debugging
+ * @copyright 2004-2008 Greg Beaver
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: ErrorStack.php,v 1.28 2008/01/03 20:26:35 cellog Exp $
+ * @link http://pear.php.net/package/PEAR_ErrorStack
+ */
+class PEAR_ErrorStack {
+ /**
+ * Errors are stored in the order that they are pushed on the stack.
+ * @since 0.4alpha Errors are no longer organized by error level.
+ * This renders pop() nearly unusable, and levels could be more easily
+ * handled in a callback anyway
+ * @var array
+ * @access private
+ */
+ var $_errors = array();
+
+ /**
+ * Storage of errors by level.
+ *
+ * Allows easy retrieval and deletion of only errors from a particular level
+ * @since PEAR 1.4.0dev
+ * @var array
+ * @access private
+ */
+ var $_errorsByLevel = array();
+
+ /**
+ * Package name this error stack represents
+ * @var string
+ * @access protected
+ */
+ var $_package;
+
+ /**
+ * Determines whether a PEAR_Error is thrown upon every error addition
+ * @var boolean
+ * @access private
+ */
+ var $_compat = false;
+
+ /**
+ * If set to a valid callback, this will be used to generate the error
+ * message from the error code, otherwise the message passed in will be
+ * used
+ * @var false|string|array
+ * @access private
+ */
+ var $_msgCallback = false;
+
+ /**
+ * If set to a valid callback, this will be used to generate the error
+ * context for an error. For PHP-related errors, this will be a file
+ * and line number as retrieved from debug_backtrace(), but can be
+ * customized for other purposes. The error might actually be in a separate
+ * configuration file, or in a database query.
+ * @var false|string|array
+ * @access protected
+ */
+ var $_contextCallback = false;
+
+ /**
+ * If set to a valid callback, this will be called every time an error
+ * is pushed onto the stack. The return value will be used to determine
+ * whether to allow an error to be pushed or logged.
+ *
+ * The return value must be one an PEAR_ERRORSTACK_* constant
+ * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
+ * @var false|string|array
+ * @access protected
+ */
+ var $_errorCallback = array();
+
+ /**
+ * PEAR::Log object for logging errors
+ * @var false|Log
+ * @access protected
+ */
+ var $_logger = false;
+
+ /**
+ * Error messages - designed to be overridden
+ * @var array
+ * @abstract
+ */
+ var $_errorMsgs = array();
+
+ /**
+ * Set up a new error stack
+ *
+ * @param string $package name of the package this error stack represents
+ * @param callback $msgCallback callback used for error message generation
+ * @param callback $contextCallback callback used for context generation,
+ * defaults to {@link getFileLine()}
+ * @param boolean $throwPEAR_Error
+ */
+ function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false,
+ $throwPEAR_Error = false)
+ {
+ $this->_package = $package;
+ $this->setMessageCallback($msgCallback);
+ $this->setContextCallback($contextCallback);
+ $this->_compat = $throwPEAR_Error;
+ }
+
+ /**
+ * Return a single error stack for this package.
+ *
+ * Note that all parameters are ignored if the stack for package $package
+ * has already been instantiated
+ * @param string $package name of the package this error stack represents
+ * @param callback $msgCallback callback used for error message generation
+ * @param callback $contextCallback callback used for context generation,
+ * defaults to {@link getFileLine()}
+ * @param boolean $throwPEAR_Error
+ * @param string $stackClass class to instantiate
+ * @static
+ * @return PEAR_ErrorStack
+ */
+ static function &singleton($package, $msgCallback = false, $contextCallback = false,
+ $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack')
+ {
+ if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
+ return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
+ }
+ if (!class_exists($stackClass)) {
+ if (function_exists('debug_backtrace')) {
+ $trace = debug_backtrace();
+ }
+ PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
+ 'exception', array('stackclass' => $stackClass),
+ 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
+ false, $trace);
+ }
+ $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
+ new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
+
+ return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
+ }
+
+ /**
+ * Internal error handler for PEAR_ErrorStack class
+ *
+ * Dies if the error is an exception (and would have died anyway)
+ * @access private
+ */
+ function _handleError($err)
+ {
+ if ($err['level'] == 'exception') {
+ $message = $err['message'];
+ if (isset($_SERVER['REQUEST_URI'])) {
+ echo ' ';
+ } else {
+ echo "\n";
+ }
+ var_dump($err['context']);
+ die($message);
+ }
+ }
+
+ /**
+ * Set up a PEAR::Log object for all error stacks that don't have one
+ * @param Log $log
+ * @static
+ */
+ static function setDefaultLogger(&$log)
+ {
+ if (is_object($log) && method_exists($log, 'log') ) {
+ $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
+ } elseif (is_callable($log)) {
+ $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
+ }
+ }
+
+ /**
+ * Set up a PEAR::Log object for this error stack
+ * @param Log $log
+ */
+ function setLogger(&$log)
+ {
+ if (is_object($log) && method_exists($log, 'log') ) {
+ $this->_logger = &$log;
+ } elseif (is_callable($log)) {
+ $this->_logger = &$log;
+ }
+ }
+
+ /**
+ * Set an error code => error message mapping callback
+ *
+ * This method sets the callback that can be used to generate error
+ * messages for any instance
+ * @param array|string Callback function/method
+ */
+ function setMessageCallback($msgCallback)
+ {
+ if (!$msgCallback) {
+ $this->_msgCallback = array(&$this, 'getErrorMessage');
+ } else {
+ if (is_callable($msgCallback)) {
+ $this->_msgCallback = $msgCallback;
+ }
+ }
+ }
+
+ /**
+ * Get an error code => error message mapping callback
+ *
+ * This method returns the current callback that can be used to generate error
+ * messages
+ * @return array|string|false Callback function/method or false if none
+ */
+ function getMessageCallback()
+ {
+ return $this->_msgCallback;
+ }
+
+ /**
+ * Sets a default callback to be used by all error stacks
+ *
+ * This method sets the callback that can be used to generate error
+ * messages for a singleton
+ * @param array|string Callback function/method
+ * @param string Package name, or false for all packages
+ * @static
+ */
+ static function setDefaultCallback($callback = false, $package = false)
+ {
+ if (!is_callable($callback)) {
+ $callback = false;
+ }
+ $package = $package ? $package : '*';
+ $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback;
+ }
+
+ /**
+ * Set a callback that generates context information (location of error) for an error stack
+ *
+ * This method sets the callback that can be used to generate context
+ * information for an error. Passing in NULL will disable context generation
+ * and remove the expensive call to debug_backtrace()
+ * @param array|string|null Callback function/method
+ */
+ function setContextCallback($contextCallback)
+ {
+ if ($contextCallback === null) {
+ return $this->_contextCallback = false;
+ }
+ if (!$contextCallback) {
+ $this->_contextCallback = array(&$this, 'getFileLine');
+ } else {
+ if (is_callable($contextCallback)) {
+ $this->_contextCallback = $contextCallback;
+ }
+ }
+ }
+
+ /**
+ * Set an error Callback
+ * If set to a valid callback, this will be called every time an error
+ * is pushed onto the stack. The return value will be used to determine
+ * whether to allow an error to be pushed or logged.
+ *
+ * The return value must be one of the ERRORSTACK_* constants.
+ *
+ * This functionality can be used to emulate PEAR's pushErrorHandling, and
+ * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of
+ * the error stack or logging
+ * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
+ * @see popCallback()
+ * @param string|array $cb
+ */
+ function pushCallback($cb)
+ {
+ array_push($this->_errorCallback, $cb);
+ }
+
+ /**
+ * Remove a callback from the error callback stack
+ * @see pushCallback()
+ * @return array|string|false
+ */
+ function popCallback()
+ {
+ if (!count($this->_errorCallback)) {
+ return false;
+ }
+ return array_pop($this->_errorCallback);
+ }
+
+ /**
+ * Set a temporary overriding error callback for every package error stack
+ *
+ * Use this to temporarily disable all existing callbacks (can be used
+ * to emulate the @ operator, for instance)
+ * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
+ * @see staticPopCallback(), pushCallback()
+ * @param string|array $cb
+ * @static
+ */
+ static function staticPushCallback($cb)
+ {
+ array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb);
+ }
+
+ /**
+ * Remove a temporary overriding error callback
+ * @see staticPushCallback()
+ * @return array|string|false
+ * @static
+ */
+ static function staticPopCallback()
+ {
+ $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']);
+ if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) {
+ $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
+ }
+ return $ret;
+ }
+
+ /**
+ * Add an error to the stack
+ *
+ * If the message generator exists, it is called with 2 parameters.
+ * - the current Error Stack object
+ * - an array that is in the same format as an error. Available indices
+ * are 'code', 'package', 'time', 'params', 'level', and 'context'
+ *
+ * Next, if the error should contain context information, this is
+ * handled by the context grabbing method.
+ * Finally, the error is pushed onto the proper error stack
+ * @param int $code Package-specific error code
+ * @param string $level Error level. This is NOT spell-checked
+ * @param array $params associative array of error parameters
+ * @param string $msg Error message, or a portion of it if the message
+ * is to be generated
+ * @param array $repackage If this error re-packages an error pushed by
+ * another package, place the array returned from
+ * {@link pop()} in this parameter
+ * @param array $backtrace Protected parameter: use this to pass in the
+ * {@link debug_backtrace()} that should be used
+ * to find error context
+ * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
+ * thrown. If a PEAR_Error is returned, the userinfo
+ * property is set to the following array:
+ *
+ *
+ * array(
+ * 'code' => $code,
+ * 'params' => $params,
+ * 'package' => $this->_package,
+ * 'level' => $level,
+ * 'time' => time(),
+ * 'context' => $context,
+ * 'message' => $msg,
+ * //['repackage' => $err] repackaged error array/Exception class
+ * );
+ *
+ *
+ * Normally, the previous array is returned.
+ */
+ function push($code, $level = 'error', $params = array(), $msg = false,
+ $repackage = false, $backtrace = false)
+ {
+ $context = false;
+ // grab error context
+ if ($this->_contextCallback) {
+ if (!$backtrace) {
+ $backtrace = debug_backtrace();
+ }
+ $context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
+ }
+
+ // save error
+ $time = explode(' ', microtime());
+ $time = $time[1] + $time[0];
+ $err = array(
+ 'code' => $code,
+ 'params' => $params,
+ 'package' => $this->_package,
+ 'level' => $level,
+ 'time' => $time,
+ 'context' => $context,
+ 'message' => $msg,
+ );
+
+ if ($repackage) {
+ $err['repackage'] = $repackage;
+ }
+
+ // set up the error message, if necessary
+ if ($this->_msgCallback) {
+ $msg = call_user_func_array($this->_msgCallback,
+ array(&$this, $err));
+ $err['message'] = $msg;
+ }
+ $push = $log = true;
+ $die = false;
+ // try the overriding callback first
+ $callback = $this->staticPopCallback();
+ if ($callback) {
+ $this->staticPushCallback($callback);
+ }
+ if (!is_callable($callback)) {
+ // try the local callback next
+ $callback = $this->popCallback();
+ if (is_callable($callback)) {
+ $this->pushCallback($callback);
+ } else {
+ // try the default callback
+ $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ?
+ $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] :
+ $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*'];
+ }
+ }
+ if (is_callable($callback)) {
+ switch(call_user_func($callback, $err)){
+ case PEAR_ERRORSTACK_IGNORE:
+ return $err;
+ break;
+ case PEAR_ERRORSTACK_PUSH:
+ $log = false;
+ break;
+ case PEAR_ERRORSTACK_LOG:
+ $push = false;
+ break;
+ case PEAR_ERRORSTACK_DIE:
+ $die = true;
+ break;
+ // anything else returned has the same effect as pushandlog
+ }
+ }
+ if ($push) {
+ array_unshift($this->_errors, $err);
+ if (!isset($this->_errorsByLevel[$err['level']])) {
+ $this->_errorsByLevel[$err['level']] = array();
+ }
+ $this->_errorsByLevel[$err['level']][] = &$this->_errors[0];
+ }
+ if ($log) {
+ if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
+ $this->_log($err);
+ }
+ }
+ if ($die) {
+ die();
+ }
+ if ($this->_compat && $push) {
+ return $this->raiseError($msg, $code, null, null, $err);
+ }
+ return $err;
+ }
+
+ /**
+ * Static version of {@link push()}
+ *
+ * @param string $package Package name this error belongs to
+ * @param int $code Package-specific error code
+ * @param string $level Error level. This is NOT spell-checked
+ * @param array $params associative array of error parameters
+ * @param string $msg Error message, or a portion of it if the message
+ * is to be generated
+ * @param array $repackage If this error re-packages an error pushed by
+ * another package, place the array returned from
+ * {@link pop()} in this parameter
+ * @param array $backtrace Protected parameter: use this to pass in the
+ * {@link debug_backtrace()} that should be used
+ * to find error context
+ * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
+ * thrown. see docs for {@link push()}
+ * @static
+ */
+ static function staticPush($package, $code, $level = 'error', $params = array(),
+ $msg = false, $repackage = false, $backtrace = false)
+ {
+ $s = &PEAR_ErrorStack::singleton($package);
+ if ($s->_contextCallback) {
+ if (!$backtrace) {
+ if (function_exists('debug_backtrace')) {
+ $backtrace = debug_backtrace();
+ }
+ }
+ }
+ return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
+ }
+
+ /**
+ * Log an error using PEAR::Log
+ * @param array $err Error array
+ * @param array $levels Error level => Log constant map
+ * @access protected
+ */
+ function _log($err)
+ {
+ if ($this->_logger) {
+ $logger = &$this->_logger;
+ } else {
+ $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'];
+ }
+ if (is_a($logger, 'Log')) {
+ $levels = array(
+ 'exception' => PEAR_LOG_CRIT,
+ 'alert' => PEAR_LOG_ALERT,
+ 'critical' => PEAR_LOG_CRIT,
+ 'error' => PEAR_LOG_ERR,
+ 'warning' => PEAR_LOG_WARNING,
+ 'notice' => PEAR_LOG_NOTICE,
+ 'info' => PEAR_LOG_INFO,
+ 'debug' => PEAR_LOG_DEBUG);
+ if (isset($levels[$err['level']])) {
+ $level = $levels[$err['level']];
+ } else {
+ $level = PEAR_LOG_INFO;
+ }
+ $logger->log($err['message'], $level, $err);
+ } else { // support non-standard logs
+ call_user_func($logger, $err);
+ }
+ }
+
+
+ /**
+ * Pop an error off of the error stack
+ *
+ * @return false|array
+ * @since 0.4alpha it is no longer possible to specify a specific error
+ * level to return - the last error pushed will be returned, instead
+ */
+ function pop()
+ {
+ $err = @array_shift($this->_errors);
+ if (!is_null($err)) {
+ @array_pop($this->_errorsByLevel[$err['level']]);
+ if (!count($this->_errorsByLevel[$err['level']])) {
+ unset($this->_errorsByLevel[$err['level']]);
+ }
+ }
+ return $err;
+ }
+
+ /**
+ * Pop an error off of the error stack, static method
+ *
+ * @param string package name
+ * @return boolean
+ * @since PEAR1.5.0a1
+ */
+ function staticPop($package)
+ {
+ if ($package) {
+ if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
+ return false;
+ }
+ return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop();
+ }
+ }
+
+ /**
+ * Determine whether there are any errors on the stack
+ * @param string|array Level name. Use to determine if any errors
+ * of level (string), or levels (array) have been pushed
+ * @return boolean
+ */
+ function hasErrors($level = false)
+ {
+ if ($level) {
+ return isset($this->_errorsByLevel[$level]);
+ }
+ return count($this->_errors);
+ }
+
+ /**
+ * Retrieve all errors since last purge
+ *
+ * @param boolean set in order to empty the error stack
+ * @param string level name, to return only errors of a particular severity
+ * @return array
+ */
+ function getErrors($purge = false, $level = false)
+ {
+ if (!$purge) {
+ if ($level) {
+ if (!isset($this->_errorsByLevel[$level])) {
+ return array();
+ } else {
+ return $this->_errorsByLevel[$level];
+ }
+ } else {
+ return $this->_errors;
+ }
+ }
+ if ($level) {
+ $ret = $this->_errorsByLevel[$level];
+ foreach ($this->_errorsByLevel[$level] as $i => $unused) {
+ // entries are references to the $_errors array
+ $this->_errorsByLevel[$level][$i] = false;
+ }
+ // array_filter removes all entries === false
+ $this->_errors = array_filter($this->_errors);
+ unset($this->_errorsByLevel[$level]);
+ return $ret;
+ }
+ $ret = $this->_errors;
+ $this->_errors = array();
+ $this->_errorsByLevel = array();
+ return $ret;
+ }
+
+ /**
+ * Determine whether there are any errors on a single error stack, or on any error stack
+ *
+ * The optional parameter can be used to test the existence of any errors without the need of
+ * singleton instantiation
+ * @param string|false Package name to check for errors
+ * @param string Level name to check for a particular severity
+ * @return boolean
+ * @static
+ */
+ static function staticHasErrors($package = false, $level = false)
+ {
+ if ($package) {
+ if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
+ return false;
+ }
+ return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level);
+ }
+ foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
+ if ($obj->hasErrors($level)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get a list of all errors since last purge, organized by package
+ * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
+ * @param boolean $purge Set to purge the error stack of existing errors
+ * @param string $level Set to a level name in order to retrieve only errors of a particular level
+ * @param boolean $merge Set to return a flat array, not organized by package
+ * @param array $sortfunc Function used to sort a merged array - default
+ * sorts by time, and should be good for most cases
+ * @static
+ * @return array
+ */
+ static function staticGetErrors($purge = false, $level = false, $merge = false,
+ $sortfunc = array('PEAR_ErrorStack', '_sortErrors'))
+ {
+ $ret = array();
+ if (!is_callable($sortfunc)) {
+ $sortfunc = array('PEAR_ErrorStack', '_sortErrors');
+ }
+ foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
+ $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level);
+ if ($test) {
+ if ($merge) {
+ $ret = array_merge($ret, $test);
+ } else {
+ $ret[$package] = $test;
+ }
+ }
+ }
+ if ($merge) {
+ usort($ret, $sortfunc);
+ }
+ return $ret;
+ }
+
+ /**
+ * Error sorting function, sorts by time
+ * @access private
+ */
+ function _sortErrors($a, $b)
+ {
+ if ($a['time'] == $b['time']) {
+ return 0;
+ }
+ if ($a['time'] < $b['time']) {
+ return 1;
+ }
+ return -1;
+ }
+
+ /**
+ * Standard file/line number/function/class context callback
+ *
+ * This function uses a backtrace generated from {@link debug_backtrace()}
+ * and so will not work at all in PHP < 4.3.0. The frame should
+ * reference the frame that contains the source of the error.
+ * @return array|false either array('file' => file, 'line' => line,
+ * 'function' => function name, 'class' => class name) or
+ * if this doesn't work, then false
+ * @param unused
+ * @param integer backtrace frame.
+ * @param array Results of debug_backtrace()
+ * @static
+ */
+ static function getFileLine($code, $params, $backtrace = null)
+ {
+ if ($backtrace === null) {
+ return false;
+ }
+ $frame = 0;
+ $functionframe = 1;
+ if (!isset($backtrace[1])) {
+ $functionframe = 0;
+ } else {
+ while (isset($backtrace[$functionframe]['function']) &&
+ $backtrace[$functionframe]['function'] == 'eval' &&
+ isset($backtrace[$functionframe + 1])) {
+ $functionframe++;
+ }
+ }
+ if (isset($backtrace[$frame])) {
+ if (!isset($backtrace[$frame]['file'])) {
+ $frame++;
+ }
+ $funcbacktrace = $backtrace[$functionframe];
+ $filebacktrace = $backtrace[$frame];
+ $ret = array('file' => $filebacktrace['file'],
+ 'line' => $filebacktrace['line']);
+ // rearrange for eval'd code or create function errors
+ if (strpos($filebacktrace['file'], '(') &&
+ preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'],
+ $matches)) {
+ $ret['file'] = $matches[1];
+ $ret['line'] = $matches[2] + 0;
+ }
+ if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
+ if ($funcbacktrace['function'] != 'eval') {
+ if ($funcbacktrace['function'] == '__lambda_func') {
+ $ret['function'] = 'create_function() code';
+ } else {
+ $ret['function'] = $funcbacktrace['function'];
+ }
+ }
+ }
+ if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
+ $ret['class'] = $funcbacktrace['class'];
+ }
+ return $ret;
+ }
+ return false;
+ }
+
+ /**
+ * Standard error message generation callback
+ *
+ * This method may also be called by a custom error message generator
+ * to fill in template values from the params array, simply
+ * set the third parameter to the error message template string to use
+ *
+ * The special variable %__msg% is reserved: use it only to specify
+ * where a message passed in by the user should be placed in the template,
+ * like so:
+ *
+ * Error message: %msg% - internal error
+ *
+ * If the message passed like so:
+ *
+ *
+ * $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
+ *
+ *
+ * The returned error message will be "Error message: server error 500 -
+ * internal error"
+ * @param PEAR_ErrorStack
+ * @param array
+ * @param string|false Pre-generated error message template
+ * @static
+ * @return string
+ */
+ static function getErrorMessage(&$stack, $err, $template = false)
+ {
+ if ($template) {
+ $mainmsg = $template;
+ } else {
+ $mainmsg = $stack->getErrorMessageTemplate($err['code']);
+ }
+ $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
+ if (is_array($err['params']) && count($err['params'])) {
+ foreach ($err['params'] as $name => $val) {
+ if (is_array($val)) {
+ // @ is needed in case $val is a multi-dimensional array
+ $val = @implode(', ', $val);
+ }
+ if (is_object($val)) {
+ if (method_exists($val, '__toString')) {
+ $val = $val->__toString();
+ } else {
+ PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING,
+ 'warning', array('obj' => get_class($val)),
+ 'object %obj% passed into getErrorMessage, but has no __toString() method');
+ $val = 'Object';
+ }
+ }
+ $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg);
+ }
+ }
+ return $mainmsg;
+ }
+
+ /**
+ * Standard Error Message Template generator from code
+ * @return string
+ */
+ function getErrorMessageTemplate($code)
+ {
+ if (!isset($this->_errorMsgs[$code])) {
+ return '%__msg%';
+ }
+ return $this->_errorMsgs[$code];
+ }
+
+ /**
+ * Set the Error Message Template array
+ *
+ * The array format must be:
+ *
';
+ return $html;
+ }
+
+ public function toText()
+ {
+ $causes = array();
+ $this->getCauseMessage($causes);
+ $causeMsg = '';
+ foreach ($causes as $i => $cause) {
+ $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': '
+ . $cause['message'] . ' in ' . $cause['file']
+ . ' on line ' . $cause['line'] . "\n";
+ }
+ return $causeMsg . $this->getTraceAsString();
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/FixPHP5PEARWarnings.php b/vendor/library/Excel/phpxls/PEAR/FixPHP5PEARWarnings.php
new file mode 100644
index 0000000..be5dc3c
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/FixPHP5PEARWarnings.php
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Frontend.php b/vendor/library/Excel/phpxls/PEAR/Frontend.php
new file mode 100644
index 0000000..de7ad24
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Frontend.php
@@ -0,0 +1,223 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Frontend.php,v 1.13 2008/01/03 20:26:35 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * Which user interface class is being used.
+ * @var string class name
+ */
+$GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI';
+
+/**
+ * Instance of $_PEAR_Command_uiclass.
+ * @var object
+ */
+$GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null;
+
+/**
+ * Singleton-based frontend for PEAR user input/output
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Frontend extends PEAR
+{
+ /**
+ * Retrieve the frontend object
+ * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk
+ * @static
+ */
+ static function &singleton($type = null)
+ {
+ if ($type === null) {
+ if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) {
+ $a = false;
+ return $a;
+ }
+ return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
+ } else {
+ $a = PEAR_Frontend::setFrontendClass($type);
+ return $a;
+ }
+ }
+
+ /**
+ * Set the frontend class that will be used by calls to {@link singleton()}
+ *
+ * Frontends are expected to conform to the PEAR naming standard of
+ * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php)
+ * @param string $uiclass full class name
+ * @return PEAR_Frontend
+ * @static
+ */
+ static function &setFrontendClass($uiclass)
+ {
+ if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
+ is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) {
+ return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
+ }
+ if (!class_exists($uiclass)) {
+ $file = str_replace('_', '/', $uiclass) . '.php';
+ if (PEAR_Frontend::isIncludeable($file)) {
+ include_once $file;
+ }
+ }
+ if (class_exists($uiclass)) {
+ $obj = &new $uiclass;
+ // quick test to see if this class implements a few of the most
+ // important frontend methods
+ if (is_a($obj, 'PEAR_Frontend')) {
+ $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj;
+ $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass;
+ return $obj;
+ } else {
+ $err = PEAR::raiseError("not a frontend class: $uiclass");
+ return $err;
+ }
+ }
+ $err = PEAR::raiseError("no such class: $uiclass");
+ return $err;
+ }
+
+ /**
+ * Set the frontend class that will be used by calls to {@link singleton()}
+ *
+ * Frontends are expected to be a descendant of PEAR_Frontend
+ * @param PEAR_Frontend
+ * @return PEAR_Frontend
+ * @static
+ */
+ static function &setFrontendObject($uiobject)
+ {
+ if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
+ is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) {
+ return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
+ }
+ if (!is_a($uiobject, 'PEAR_Frontend')) {
+ $err = PEAR::raiseError('not a valid frontend class: (' .
+ get_class($uiobject) . ')');
+ return $err;
+ }
+ $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject;
+ $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject);
+ return $uiobject;
+ }
+
+ /**
+ * @param string $path relative or absolute include path
+ * @return boolean
+ * @static
+ */
+ static function isIncludeable($path)
+ {
+ if (file_exists($path) && is_readable($path)) {
+ return true;
+ }
+ $fp = @fopen($path, 'r', true);
+ if ($fp) {
+ fclose($fp);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param PEAR_Config
+ */
+ function setConfig(&$config)
+ {
+ }
+
+ /**
+ * This can be overridden to allow session-based temporary file management
+ *
+ * By default, all files are deleted at the end of a session. The web installer
+ * needs to be able to sustain a list over many sessions in order to support
+ * user interaction with install scripts
+ */
+ function addTempFile($file)
+ {
+ $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
+ }
+
+ /**
+ * Log an action
+ *
+ * @param string $msg the message to log
+ * @param boolean $append_crlf
+ * @return boolean true
+ * @abstract
+ */
+ function log($msg, $append_crlf = true)
+ {
+ }
+
+ /**
+ * Run a post-installation script
+ *
+ * @param array $scripts array of post-install scripts
+ * @abstract
+ */
+ function runPostinstallScripts(&$scripts)
+ {
+ }
+
+ /**
+ * Display human-friendly output formatted depending on the
+ * $command parameter.
+ *
+ * This should be able to handle basic output data with no command
+ * @param mixed $data data structure containing the information to display
+ * @param string $command command from which this method was called
+ * @abstract
+ */
+ function outputData($data, $command = '_default')
+ {
+ }
+
+ /**
+ * Display a modal form dialog and return the given input
+ *
+ * A frontend that requires multiple requests to retrieve and process
+ * data must take these needs into account, and implement the request
+ * handling code.
+ * @param string $command command from which this method was called
+ * @param array $prompts associative array. keys are the input field names
+ * and values are the description
+ * @param array $types array of input field types (text, password,
+ * etc.) keys have to be the same like in $prompts
+ * @param array $defaults array of default values. again keys have
+ * to be the same like in $prompts. Do not depend
+ * on a default value being set.
+ * @return array input sent by the user
+ * @abstract
+ */
+ function userDialog($command, $prompts, $types = array(), $defaults = array())
+ {
+ }
+}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Frontend/CLI.php b/vendor/library/Excel/phpxls/PEAR/Frontend/CLI.php
new file mode 100644
index 0000000..0655aba
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Frontend/CLI.php
@@ -0,0 +1,794 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: CLI.php,v 1.68 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+/**
+ * base class
+ */
+require_once 'PEAR/Frontend.php';
+
+/**
+ * Command-line Frontend for the PEAR Installer
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Frontend_CLI extends PEAR_Frontend
+{
+ // {{{ properties
+
+ /**
+ * What type of user interface this frontend is for.
+ * @var string
+ * @access public
+ */
+ var $type = 'CLI';
+ var $lp = ''; // line prefix
+
+ var $params = array();
+ var $term = array(
+ 'bold' => '',
+ 'normal' => '',
+ );
+
+ // }}}
+
+ // {{{ constructor
+
+ function PEAR_Frontend_CLI()
+ {
+ parent::PEAR();
+ $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1
+ if (function_exists('posix_isatty') && !posix_isatty(1)) {
+ // output is being redirected to a file or through a pipe
+ } elseif ($term) {
+ // XXX can use ncurses extension here, if available
+ if (preg_match('/^(xterm|vt220|linux)/', $term)) {
+ $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109);
+ $this->term['normal']=sprintf("%c%c%c", 27, 91, 109);
+ } elseif (preg_match('/^vt100/', $term)) {
+ $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0);
+ $this->term['normal']=sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0);
+ }
+ } elseif (OS_WINDOWS) {
+ // XXX add ANSI codes here
+ }
+ }
+
+ // }}}
+
+ // {{{ displayLine(text)
+
+ function displayLine($text)
+ {
+ trigger_error("PEAR_Frontend_CLI::displayLine deprecated", E_USER_ERROR);
+ }
+
+ function _displayLine($text)
+ {
+ print "$this->lp$text\n";
+ }
+
+ // }}}
+ // {{{ display(text)
+
+ function display($text)
+ {
+ trigger_error("PEAR_Frontend_CLI::display deprecated", E_USER_ERROR);
+ }
+
+ function _display($text)
+ {
+ print $text;
+ }
+
+ // }}}
+ // {{{ displayError(eobj)
+
+ /**
+ * @param object PEAR_Error object
+ */
+ function displayError($eobj)
+ {
+ return $this->_displayLine($eobj->getMessage());
+ }
+
+ // }}}
+ // {{{ displayFatalError(eobj)
+
+ /**
+ * @param object PEAR_Error object
+ */
+ function displayFatalError($eobj)
+ {
+ $this->displayError($eobj);
+ if (class_exists('PEAR_Config')) {
+ $config = &PEAR_Config::singleton();
+ if ($config->get('verbose') > 5) {
+ if (function_exists('debug_print_backtrace')) {
+ debug_print_backtrace();
+ } elseif (function_exists('debug_backtrace')) {
+ $trace = debug_backtrace();
+ $raised = false;
+ foreach ($trace as $i => $frame) {
+ if (!$raised) {
+ if (isset($frame['class']) && strtolower($frame['class']) ==
+ 'pear' && strtolower($frame['function']) == 'raiseerror') {
+ $raised = true;
+ } else {
+ continue;
+ }
+ }
+ if (!isset($frame['class'])) {
+ $frame['class'] = '';
+ }
+ if (!isset($frame['type'])) {
+ $frame['type'] = '';
+ }
+ if (!isset($frame['function'])) {
+ $frame['function'] = '';
+ }
+ if (!isset($frame['line'])) {
+ $frame['line'] = '';
+ }
+ $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]");
+ }
+ }
+ }
+ }
+ exit(1);
+ }
+
+ // }}}
+ // {{{ displayHeading(title)
+
+ function displayHeading($title)
+ {
+ trigger_error("PEAR_Frontend_CLI::displayHeading deprecated", E_USER_ERROR);
+ }
+
+ function _displayHeading($title)
+ {
+ print $this->lp.$this->bold($title)."\n";
+ print $this->lp.str_repeat("=", strlen($title))."\n";
+ }
+
+ // }}}
+
+ /**
+ * Instruct the runInstallScript method to skip a paramgroup that matches the
+ * id value passed in.
+ *
+ * This method is useful for dynamically configuring which sections of a post-install script
+ * will be run based on the user's setup, which is very useful for making flexible
+ * post-install scripts without losing the cross-Frontend ability to retrieve user input
+ * @param string
+ */
+ function skipParamgroup($id)
+ {
+ $this->_skipSections[$id] = true;
+ }
+
+ function runPostinstallScripts(&$scripts)
+ {
+ foreach ($scripts as $i => $script) {
+ $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj);
+ }
+ }
+
+ /**
+ * @param array $xml contents of postinstallscript tag
+ * @param object $script post-installation script
+ * @param string install|upgrade
+ */
+ function runInstallScript($xml, &$script)
+ {
+ $this->_skipSections = array();
+ if (!is_array($xml) || !isset($xml['paramgroup'])) {
+ $script->run(array(), '_default');
+ } else {
+ $completedPhases = array();
+ if (!isset($xml['paramgroup'][0])) {
+ $xml['paramgroup'] = array($xml['paramgroup']);
+ }
+ foreach ($xml['paramgroup'] as $group) {
+ if (isset($this->_skipSections[$group['id']])) {
+ // the post-install script chose to skip this section dynamically
+ continue;
+ }
+ if (isset($group['name'])) {
+ $paramname = explode('::', $group['name']);
+ if ($lastgroup['id'] != $paramname[0]) {
+ continue;
+ }
+ $group['name'] = $paramname[1];
+ if (isset($answers)) {
+ if (isset($answers[$group['name']])) {
+ switch ($group['conditiontype']) {
+ case '=' :
+ if ($answers[$group['name']] != $group['value']) {
+ continue 2;
+ }
+ break;
+ case '!=' :
+ if ($answers[$group['name']] == $group['value']) {
+ continue 2;
+ }
+ break;
+ case 'preg_match' :
+ if (!@preg_match('/' . $group['value'] . '/',
+ $answers[$group['name']])) {
+ continue 2;
+ }
+ break;
+ default :
+ return;
+ }
+ }
+ } else {
+ return;
+ }
+ }
+ $lastgroup = $group;
+ if (isset($group['instructions'])) {
+ $this->_display($group['instructions']);
+ }
+ if (!isset($group['param'][0])) {
+ $group['param'] = array($group['param']);
+ }
+ if (isset($group['param'])) {
+ if (method_exists($script, 'postProcessPrompts')) {
+ $prompts = $script->postProcessPrompts($group['param'], $group['id']);
+ if (!is_array($prompts) || count($prompts) != count($group['param'])) {
+ $this->outputData('postinstall', 'Error: post-install script did not ' .
+ 'return proper post-processed prompts');
+ $prompts = $group['param'];
+ } else {
+ foreach ($prompts as $i => $var) {
+ if (!is_array($var) || !isset($var['prompt']) ||
+ !isset($var['name']) ||
+ ($var['name'] != $group['param'][$i]['name']) ||
+ ($var['type'] != $group['param'][$i]['type'])) {
+ $this->outputData('postinstall', 'Error: post-install script ' .
+ 'modified the variables or prompts, severe security risk. ' .
+ 'Will instead use the defaults from the package.xml');
+ $prompts = $group['param'];
+ }
+ }
+ }
+ $answers = $this->confirmDialog($prompts);
+ } else {
+ $answers = $this->confirmDialog($group['param']);
+ }
+ }
+ if ((isset($answers) && $answers) || !isset($group['param'])) {
+ if (!isset($answers)) {
+ $answers = array();
+ }
+ array_unshift($completedPhases, $group['id']);
+ if (!$script->run($answers, $group['id'])) {
+ $script->run($completedPhases, '_undoOnError');
+ return;
+ }
+ } else {
+ $script->run($completedPhases, '_undoOnError');
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Ask for user input, confirm the answers and continue until the user is satisfied
+ * @param array an array of arrays, format array('name' => 'paramname', 'prompt' =>
+ * 'text to display', 'type' => 'string'[, default => 'default value'])
+ * @return array
+ */
+ function confirmDialog($params)
+ {
+ $answers = array();
+ $prompts = $types = array();
+ foreach ($params as $param) {
+ $prompts[$param['name']] = $param['prompt'];
+ $types[$param['name']] = $param['type'];
+ if (isset($param['default'])) {
+ $answers[$param['name']] = $param['default'];
+ } else {
+ $answers[$param['name']] = '';
+ }
+ }
+ $tried = false;
+ do {
+ if ($tried) {
+ $i = 1;
+ foreach ($answers as $var => $value) {
+ if (!strlen($value)) {
+ echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n");
+ }
+ $i++;
+ }
+ }
+ $answers = $this->userDialog('', $prompts, $types, $answers);
+ $tried = true;
+ } while (is_array($answers) && count(array_filter($answers)) != count($prompts));
+ return $answers;
+ }
+ // {{{ userDialog(prompt, [type], [default])
+
+ function userDialog($command, $prompts, $types = array(), $defaults = array(),
+ $screensize = 20)
+ {
+ if (!is_array($prompts)) {
+ return array();
+ }
+ $testprompts = array_keys($prompts);
+ $result = $defaults;
+ if (!defined('STDIN')) {
+ $fp = fopen('php://stdin', 'r');
+ } else {
+ $fp = STDIN;
+ }
+ reset($prompts);
+ if (count($prompts) == 1 && $types[key($prompts)] == 'yesno') {
+ foreach ($prompts as $key => $prompt) {
+ $type = $types[$key];
+ $default = @$defaults[$key];
+ print "$prompt ";
+ if ($default) {
+ print "[$default] ";
+ }
+ print ": ";
+ if (version_compare(phpversion(), '5.0.0', '<')) {
+ $line = fgets($fp, 2048);
+ } else {
+ if (!defined('STDIN')) {
+ define('STDIN', fopen('php://stdin', 'r'));
+ }
+ $line = fgets(STDIN, 2048);
+ }
+ if ($default && trim($line) == "") {
+ $result[$key] = $default;
+ } else {
+ $result[$key] = trim($line);
+ }
+ }
+ return $result;
+ }
+ while (true) {
+ $descLength = max(array_map('strlen', $prompts));
+ $descFormat = "%-{$descLength}s";
+ $last = count($prompts);
+
+ $i = 0;
+ foreach ($prompts as $n => $var) {
+ printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], isset($result[$n]) ?
+ $result[$n] : null);
+ }
+
+ print "\n1-$last, 'all', 'abort', or Enter to continue: ";
+ $tmp = trim(fgets($fp, 1024));
+ if (empty($tmp)) {
+ break;
+ }
+ if ($tmp == 'abort') {
+ return false;
+ }
+ if (isset($testprompts[(int)$tmp - 1])) {
+ $var = $testprompts[(int)$tmp - 1];
+ $desc = $prompts[$var];
+ $current = @$result[$var];
+ print "$desc [$current] : ";
+ $tmp = trim(fgets($fp, 1024));
+ if (trim($tmp) !== '') {
+ $result[$var] = trim($tmp);
+ }
+ } elseif ($tmp == 'all') {
+ foreach ($prompts as $var => $desc) {
+ $current = $result[$var];
+ print "$desc [$current] : ";
+ $tmp = trim(fgets($fp, 1024));
+ if (trim($tmp) !== '') {
+ $result[$var] = trim($tmp);
+ }
+ }
+ }
+ }
+ if (!defined('STDIN')) {
+ fclose($fp);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ userConfirm(prompt, [default])
+
+ function userConfirm($prompt, $default = 'yes')
+ {
+ trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR);
+ static $positives = array('y', 'yes', 'on', '1');
+ static $negatives = array('n', 'no', 'off', '0');
+ print "$this->lp$prompt [$default] : ";
+ $fp = fopen("php://stdin", "r");
+ $line = fgets($fp, 2048);
+ fclose($fp);
+ $answer = strtolower(trim($line));
+ if (empty($answer)) {
+ $answer = $default;
+ }
+ if (in_array($answer, $positives)) {
+ return true;
+ }
+ if (in_array($answer, $negatives)) {
+ return false;
+ }
+ if (in_array($default, $positives)) {
+ return true;
+ }
+ return false;
+ }
+
+ // }}}
+ // {{{ startTable([params])
+
+ function startTable($params = array())
+ {
+ trigger_error("PEAR_Frontend_CLI::startTable deprecated", E_USER_ERROR);
+ }
+
+ function _startTable($params = array())
+ {
+ $params['table_data'] = array();
+ $params['widest'] = array(); // indexed by column
+ $params['highest'] = array(); // indexed by row
+ $params['ncols'] = 0;
+ $this->params = $params;
+ }
+
+ // }}}
+ // {{{ tableRow(columns, [rowparams], [colparams])
+
+ function tableRow($columns, $rowparams = array(), $colparams = array())
+ {
+ trigger_error("PEAR_Frontend_CLI::tableRow deprecated", E_USER_ERROR);
+ }
+
+ function _tableRow($columns, $rowparams = array(), $colparams = array())
+ {
+ $highest = 1;
+ for ($i = 0; $i < sizeof($columns); $i++) {
+ $col = &$columns[$i];
+ if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) {
+ $col = wordwrap($col, $colparams[$i]['wrap'], "\n", 0);
+ }
+ if (strpos($col, "\n") !== false) {
+ $multiline = explode("\n", $col);
+ $w = 0;
+ foreach ($multiline as $n => $line) {
+ if (strlen($line) > $w) {
+ $w = strlen($line);
+ }
+ }
+ $lines = sizeof($multiline);
+ } else {
+ $w = strlen($col);
+ }
+
+ if (isset($this->params['widest'][$i])) {
+ if ($w > $this->params['widest'][$i]) {
+ $this->params['widest'][$i] = $w;
+ }
+ } else {
+ $this->params['widest'][$i] = $w;
+ }
+ $tmp = count_chars($columns[$i], 1);
+ // handle unix, mac and windows formats
+ $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1;
+ if ($lines > $highest) {
+ $highest = $lines;
+ }
+ }
+ if (sizeof($columns) > $this->params['ncols']) {
+ $this->params['ncols'] = sizeof($columns);
+ }
+ $new_row = array(
+ 'data' => $columns,
+ 'height' => $highest,
+ 'rowparams' => $rowparams,
+ 'colparams' => $colparams,
+ );
+ $this->params['table_data'][] = $new_row;
+ }
+
+ // }}}
+ // {{{ endTable()
+
+ function endTable()
+ {
+ trigger_error("PEAR_Frontend_CLI::endTable deprecated", E_USER_ERROR);
+ }
+
+ function _endTable()
+ {
+ extract($this->params);
+ if (!empty($caption)) {
+ $this->_displayHeading($caption);
+ }
+ if (count($table_data) == 0) {
+ return;
+ }
+ if (!isset($width)) {
+ $width = $widest;
+ } else {
+ for ($i = 0; $i < $ncols; $i++) {
+ if (!isset($width[$i])) {
+ $width[$i] = $widest[$i];
+ }
+ }
+ }
+ $border = false;
+ if (empty($border)) {
+ $cellstart = '';
+ $cellend = ' ';
+ $rowend = '';
+ $padrowend = false;
+ $borderline = '';
+ } else {
+ $cellstart = '| ';
+ $cellend = ' ';
+ $rowend = '|';
+ $padrowend = true;
+ $borderline = '+';
+ foreach ($width as $w) {
+ $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1);
+ $borderline .= '+';
+ }
+ }
+ if ($borderline) {
+ $this->_displayLine($borderline);
+ }
+ for ($i = 0; $i < sizeof($table_data); $i++) {
+ extract($table_data[$i]);
+ if (!is_array($rowparams)) {
+ $rowparams = array();
+ }
+ if (!is_array($colparams)) {
+ $colparams = array();
+ }
+ $rowlines = array();
+ if ($height > 1) {
+ for ($c = 0; $c < sizeof($data); $c++) {
+ $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]);
+ if (sizeof($rowlines[$c]) < $height) {
+ $rowlines[$c] = array_pad($rowlines[$c], $height, '');
+ }
+ }
+ } else {
+ for ($c = 0; $c < sizeof($data); $c++) {
+ $rowlines[$c] = array($data[$c]);
+ }
+ }
+ for ($r = 0; $r < $height; $r++) {
+ $rowtext = '';
+ for ($c = 0; $c < sizeof($data); $c++) {
+ if (isset($colparams[$c])) {
+ $attribs = array_merge($rowparams, $colparams);
+ } else {
+ $attribs = $rowparams;
+ }
+ $w = isset($width[$c]) ? $width[$c] : 0;
+ //$cell = $data[$c];
+ $cell = $rowlines[$c][$r];
+ $l = strlen($cell);
+ if ($l > $w) {
+ $cell = substr($cell, 0, $w);
+ }
+ if (isset($attribs['bold'])) {
+ $cell = $this->bold($cell);
+ }
+ if ($l < $w) {
+ // not using str_pad here because we may
+ // add bold escape characters to $cell
+ $cell .= str_repeat(' ', $w - $l);
+ }
+
+ $rowtext .= $cellstart . $cell . $cellend;
+ }
+ if (!$border) {
+ $rowtext = rtrim($rowtext);
+ }
+ $rowtext .= $rowend;
+ $this->_displayLine($rowtext);
+ }
+ }
+ if ($borderline) {
+ $this->_displayLine($borderline);
+ }
+ }
+
+ // }}}
+ // {{{ outputData()
+
+ function outputData($data, $command = '_default')
+ {
+ switch ($command) {
+ case 'channel-info':
+ foreach ($data as $type => $section) {
+ if ($type == 'main') {
+ $section['data'] = array_values($section['data']);
+ }
+ $this->outputData($section);
+ }
+ break;
+ case 'install':
+ case 'upgrade':
+ case 'upgrade-all':
+ if (isset($data['release_warnings'])) {
+ $this->_displayLine('');
+ $this->_startTable(array(
+ 'border' => false,
+ 'caption' => 'Release Warnings'
+ ));
+ $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55)));
+ $this->_endTable();
+ $this->_displayLine('');
+ }
+ $this->_displayLine($data['data']);
+ break;
+ case 'search':
+ $this->_startTable($data);
+ if (isset($data['headline']) && is_array($data['headline'])) {
+ $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
+ }
+
+ foreach($data['data'] as $category) {
+ foreach($category as $pkg) {
+ $this->_tableRow($pkg, null, array(1 => array('wrap' => 55)));
+ }
+ };
+ $this->_endTable();
+ break;
+ case 'list-all':
+ if (!isset($data['data'])) {
+ $this->_displayLine('No packages in channel');
+ break;
+ }
+ $this->_startTable($data);
+ if (isset($data['headline']) && is_array($data['headline'])) {
+ $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
+ }
+
+ foreach($data['data'] as $category) {
+ foreach($category as $pkg) {
+ unset($pkg[4]);
+ unset($pkg[5]);
+ $this->_tableRow($pkg, null, array(1 => array('wrap' => 55)));
+ }
+ };
+ $this->_endTable();
+ break;
+ case 'config-show':
+ $data['border'] = false;
+ $opts = array(0 => array('wrap' => 30),
+ 1 => array('wrap' => 20),
+ 2 => array('wrap' => 35));
+ $this->_startTable($data);
+ if (isset($data['headline']) && is_array($data['headline'])) {
+ $this->_tableRow($data['headline'],
+ array('bold' => true),
+ $opts);
+ }
+ foreach($data['data'] as $group) {
+ foreach($group as $value) {
+ if ($value[2] == '') {
+ $value[2] = "";
+ }
+ $this->_tableRow($value, null, $opts);
+ }
+ }
+ $this->_endTable();
+ break;
+ case 'remote-info':
+ $d = $data;
+ $data = array(
+ 'caption' => 'Package details:',
+ 'border' => false,
+ 'data' => array(
+ array("Latest", $data['stable']),
+ array("Installed", $data['installed']),
+ array("Package", $data['name']),
+ array("License", $data['license']),
+ array("Category", $data['category']),
+ array("Summary", $data['summary']),
+ array("Description", $data['description']),
+ ),
+ );
+ if (isset($d['deprecated']) && $d['deprecated']) {
+ $conf = &PEAR_Config::singleton();
+ $reg = $conf->getRegistry();
+ $name = $reg->parsedPackageNameToString($d['deprecated'], true);
+ $data['data'][] = array('Deprecated! use', $name);
+ }
+ default: {
+ if (is_array($data)) {
+ $this->_startTable($data);
+ $count = count($data['data'][0]);
+ if ($count == 2) {
+ $opts = array(0 => array('wrap' => 25),
+ 1 => array('wrap' => 48)
+ );
+ } elseif ($count == 3) {
+ $opts = array(0 => array('wrap' => 30),
+ 1 => array('wrap' => 20),
+ 2 => array('wrap' => 35)
+ );
+ } else {
+ $opts = null;
+ }
+ if (isset($data['headline']) && is_array($data['headline'])) {
+ $this->_tableRow($data['headline'],
+ array('bold' => true),
+ $opts);
+ }
+ foreach($data['data'] as $row) {
+ $this->_tableRow($row, null, $opts);
+ }
+ $this->_endTable();
+ } else {
+ $this->_displayLine($data);
+ }
+ }
+ }
+ }
+
+ // }}}
+ // {{{ log(text)
+
+
+ function log($text, $append_crlf = true)
+ {
+ if ($append_crlf) {
+ return $this->_displayLine($text);
+ }
+ return $this->_display($text);
+ }
+
+
+ // }}}
+ // {{{ bold($text)
+
+ function bold($text)
+ {
+ if (empty($this->term['bold'])) {
+ return strtoupper($text);
+ }
+ return $this->term['bold'] . $text . $this->term['normal'];
+ }
+
+ // }}}
+}
+
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer.php b/vendor/library/Excel/phpxls/PEAR/Installer.php
new file mode 100644
index 0000000..d3f3162
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer.php
@@ -0,0 +1,1723 @@
+
+ * @author Tomas V.V. Cox
+ * @author Martin Jansen
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Installer.php,v 1.253 2008/05/13 22:46:07 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * Used for installation groups in package.xml 2.0 and platform exceptions
+ */
+require_once 'OS/Guess.php';
+require_once 'PEAR/Downloader.php';
+
+define('PEAR_INSTALLER_NOBINARY', -240);
+/**
+ * Administration class used to install PEAR packages and maintain the
+ * installed package database.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Tomas V.V. Cox
+ * @author Martin Jansen
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Installer extends PEAR_Downloader
+{
+ // {{{ properties
+
+ /** name of the package directory, for example Foo-1.0
+ * @var string
+ */
+ var $pkgdir;
+
+ /** directory where PHP code files go
+ * @var string
+ */
+ var $phpdir;
+
+ /** directory where PHP extension files go
+ * @var string
+ */
+ var $extdir;
+
+ /** directory where documentation goes
+ * @var string
+ */
+ var $docdir;
+
+ /** installation root directory (ala PHP's INSTALL_ROOT or
+ * automake's DESTDIR
+ * @var string
+ */
+ var $installroot = '';
+
+ /** debug level
+ * @var int
+ */
+ var $debug = 1;
+
+ /** temporary directory
+ * @var string
+ */
+ var $tmpdir;
+
+ /**
+ * PEAR_Registry object used by the installer
+ * @var PEAR_Registry
+ */
+ var $registry;
+
+ /**
+ * array of PEAR_Downloader_Packages
+ * @var array
+ */
+ var $_downloadedPackages;
+
+ /** List of file transactions queued for an install/upgrade/uninstall.
+ *
+ * Format:
+ * array(
+ * 0 => array("rename => array("from-file", "to-file")),
+ * 1 => array("delete" => array("file-to-delete")),
+ * ...
+ * )
+ *
+ * @var array
+ */
+ var $file_operations = array();
+
+ // }}}
+
+ // {{{ constructor
+
+ /**
+ * PEAR_Installer constructor.
+ *
+ * @param object $ui user interface object (instance of PEAR_Frontend_*)
+ *
+ * @access public
+ */
+ function PEAR_Installer(&$ui)
+ {
+ parent::PEAR_Common();
+ $this->setFrontendObject($ui);
+ $this->debug = $this->config->get('verbose');
+ }
+
+ function setOptions($options)
+ {
+ $this->_options = $options;
+ }
+
+ function setConfig(&$config)
+ {
+ $this->config = &$config;
+ $this->_registry = &$config->getRegistry();
+ }
+
+ // }}}
+
+ function _removeBackups($files)
+ {
+ foreach ($files as $path) {
+ $this->addFileOperation('removebackup', array($path));
+ }
+ }
+
+ // {{{ _deletePackageFiles()
+
+ /**
+ * Delete a package's installed files, does not remove empty directories.
+ *
+ * @param string package name
+ * @param string channel name
+ * @param bool if true, then files are backed up first
+ * @return bool TRUE on success, or a PEAR error on failure
+ * @access protected
+ */
+ function _deletePackageFiles($package, $channel = false, $backup = false)
+ {
+ if (!$channel) {
+ $channel = 'pear.php.net';
+ }
+ if (!strlen($package)) {
+ return $this->raiseError("No package to uninstall given");
+ }
+ if (strtolower($package) == 'pear' && $channel == 'pear.php.net') {
+ // to avoid race conditions, include all possible needed files
+ require_once 'PEAR/Task/Common.php';
+ require_once 'PEAR/Task/Replace.php';
+ require_once 'PEAR/Task/Unixeol.php';
+ require_once 'PEAR/Task/Windowseol.php';
+ require_once 'PEAR/PackageFile/v1.php';
+ require_once 'PEAR/PackageFile/v2.php';
+ require_once 'PEAR/PackageFile/Generator/v1.php';
+ require_once 'PEAR/PackageFile/Generator/v2.php';
+ }
+ $filelist = $this->_registry->packageInfo($package, 'filelist', $channel);
+ if ($filelist == null) {
+ return $this->raiseError("$channel/$package not installed");
+ }
+ $ret = array();
+ foreach ($filelist as $file => $props) {
+ if (empty($props['installed_as'])) {
+ continue;
+ }
+ $path = $props['installed_as'];
+ if ($backup) {
+ $this->addFileOperation('backup', array($path));
+ $ret[] = $path;
+ }
+ $this->addFileOperation('delete', array($path));
+ }
+ if ($backup) {
+ return $ret;
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ _installFile()
+
+ /**
+ * @param string filename
+ * @param array attributes from tag in package.xml
+ * @param string path to install the file in
+ * @param array options from command-line
+ * @access private
+ */
+ function _installFile($file, $atts, $tmp_path, $options)
+ {
+ // {{{ return if this file is meant for another platform
+ static $os;
+ if (!isset($this->_registry)) {
+ $this->_registry = &$this->config->getRegistry();
+ }
+ if (isset($atts['platform'])) {
+ if (empty($os)) {
+ $os = new OS_Guess();
+ }
+ if (strlen($atts['platform']) && $atts['platform']{0} == '!') {
+ $negate = true;
+ $platform = substr($atts['platform'], 1);
+ } else {
+ $negate = false;
+ $platform = $atts['platform'];
+ }
+ if ((bool) $os->matchSignature($platform) === $negate) {
+ $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")");
+ return PEAR_INSTALLER_SKIPPED;
+ }
+ }
+ // }}}
+
+ $channel = $this->pkginfo->getChannel();
+ // {{{ assemble the destination paths
+ switch ($atts['role']) {
+ case 'src':
+ case 'extsrc':
+ $this->source_files++;
+ return;
+ case 'doc':
+ case 'data':
+ case 'test':
+ $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) .
+ DIRECTORY_SEPARATOR . $this->pkginfo->getPackage();
+ unset($atts['baseinstalldir']);
+ break;
+ case 'ext':
+ case 'php':
+ $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel);
+ break;
+ case 'script':
+ $dest_dir = $this->config->get('bin_dir', null, $channel);
+ break;
+ default:
+ return $this->raiseError("Invalid role `$atts[role]' for file $file");
+ }
+ $save_destdir = $dest_dir;
+ if (!empty($atts['baseinstalldir'])) {
+ $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
+ }
+ if (dirname($file) != '.' && empty($atts['install-as'])) {
+ $dest_dir .= DIRECTORY_SEPARATOR . dirname($file);
+ }
+ if (empty($atts['install-as'])) {
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file);
+ } else {
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as'];
+ }
+ $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file;
+
+ // Clean up the DIRECTORY_SEPARATOR mess
+ $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
+ list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
+ array(DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR),
+ array($dest_file, $orig_file));
+ $final_dest_file = $installed_as = $dest_file;
+ if (isset($this->_options['packagingroot'])) {
+ $installedas_dest_dir = dirname($final_dest_file);
+ $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+ $final_dest_file = $this->_prependPath($final_dest_file,
+ $this->_options['packagingroot']);
+ } else {
+ $installedas_dest_dir = dirname($final_dest_file);
+ $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+ }
+ $dest_dir = dirname($final_dest_file);
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+ if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) {
+ return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED);
+ }
+ // }}}
+
+ if (empty($this->_options['register-only']) &&
+ (!file_exists($dest_dir) || !is_dir($dest_dir))) {
+ if (!$this->mkDirHier($dest_dir)) {
+ return $this->raiseError("failed to mkdir $dest_dir",
+ PEAR_INSTALLER_FAILED);
+ }
+ $this->log(3, "+ mkdir $dest_dir");
+ }
+ // pretty much nothing happens if we are only registering the install
+ if (empty($this->_options['register-only'])) {
+ if (empty($atts['replacements'])) {
+ if (!file_exists($orig_file)) {
+ return $this->raiseError("file $orig_file does not exist",
+ PEAR_INSTALLER_FAILED);
+ }
+ if (!@copy($orig_file, $dest_file)) {
+ return $this->raiseError("failed to write $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+ $this->log(3, "+ cp $orig_file $dest_file");
+ if (isset($atts['md5sum'])) {
+ $md5sum = md5_file($dest_file);
+ }
+ } else {
+ // {{{ file with replacements
+ if (!file_exists($orig_file)) {
+ return $this->raiseError("file does not exist",
+ PEAR_INSTALLER_FAILED);
+ }
+ $contents = file_get_contents($orig_file);
+ if ($contents === false) {
+ $contents = '';
+ }
+ if (isset($atts['md5sum'])) {
+ $md5sum = md5($contents);
+ }
+ $subst_from = $subst_to = array();
+ foreach ($atts['replacements'] as $a) {
+ $to = '';
+ if ($a['type'] == 'php-const') {
+ if (preg_match('/^[a-z0-9_]+\\z/i', $a['to'])) {
+ eval("\$to = $a[to];");
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "invalid php-const replacement: $a[to]");
+ }
+ continue;
+ }
+ } elseif ($a['type'] == 'pear-config') {
+ if ($a['to'] == 'master_server') {
+ $chan = $this->_registry->getChannel($channel);
+ if (!PEAR::isError($chan)) {
+ $to = $chan->getServer();
+ } else {
+ $to = $this->config->get($a['to'], null, $channel);
+ }
+ } else {
+ $to = $this->config->get($a['to'], null, $channel);
+ }
+ if (is_null($to)) {
+ if (!isset($options['soft'])) {
+ $this->log(0, "invalid pear-config replacement: $a[to]");
+ }
+ continue;
+ }
+ } elseif ($a['type'] == 'package-info') {
+ if ($t = $this->pkginfo->packageInfo($a['to'])) {
+ $to = $t;
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "invalid package-info replacement: $a[to]");
+ }
+ continue;
+ }
+ }
+ if (!is_null($to)) {
+ $subst_from[] = $a['from'];
+ $subst_to[] = $to;
+ }
+ }
+ $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file");
+ if (sizeof($subst_from)) {
+ $contents = str_replace($subst_from, $subst_to, $contents);
+ }
+ $wp = @fopen($dest_file, "wb");
+ if (!is_resource($wp)) {
+ return $this->raiseError("failed to create $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+ if (@fwrite($wp, $contents) === false) {
+ return $this->raiseError("failed writing to $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+ fclose($wp);
+ // }}}
+ }
+ // {{{ check the md5
+ if (isset($md5sum)) {
+ if (strtolower($md5sum) === strtolower($atts['md5sum'])) {
+ $this->log(2, "md5sum ok: $final_dest_file");
+ } else {
+ if (empty($options['force'])) {
+ // delete the file
+ if (file_exists($dest_file)) {
+ unlink($dest_file);
+ }
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError("bad md5sum for file $final_dest_file",
+ PEAR_INSTALLER_FAILED);
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ }
+ }
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ }
+ }
+ }
+ }
+ // }}}
+ // {{{ set file permissions
+ if (!OS_WINDOWS) {
+ if ($atts['role'] == 'script') {
+ $mode = 0777 & ~(int)octdec($this->config->get('umask'));
+ $this->log(3, "+ chmod +x $dest_file");
+ } else {
+ $mode = 0666 & ~(int)octdec($this->config->get('umask'));
+ }
+ if ($atts['role'] != 'src') {
+ $this->addFileOperation("chmod", array($mode, $dest_file));
+ if (!@chmod($dest_file, $mode)) {
+ if (!isset($options['soft'])) {
+ $this->log(0, "failed to change mode of $dest_file: $php_errormsg");
+ }
+ }
+ }
+ }
+ // }}}
+ if ($atts['role'] == 'src') {
+ rename($dest_file, $final_dest_file);
+ $this->log(2, "renamed source file $dest_file to $final_dest_file");
+ } else {
+ $this->addFileOperation("rename", array($dest_file, $final_dest_file,
+ $atts['role'] == 'ext'));
+ }
+ }
+ // Store the full path where the file was installed for easy unistall
+ if ($atts['role'] != 'script') {
+ $loc = $this->config->get($atts['role'] . '_dir');
+ } else {
+ $loc = $this->config->get('bin_dir');
+ }
+ if ($atts['role'] != 'src') {
+ $this->addFileOperation("installed_as", array($file, $installed_as,
+ $loc,
+ dirname(substr($installedas_dest_file, strlen($loc)))));
+ }
+
+ //$this->log(2, "installed: $dest_file");
+ return PEAR_INSTALLER_OK;
+ }
+
+ // }}}
+ // {{{ _installFile2()
+
+ /**
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @param string filename
+ * @param array attributes from tag in package.xml
+ * @param string path to install the file in
+ * @param array options from command-line
+ * @access private
+ */
+ function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options)
+ {
+ $atts = $real_atts;
+ if (!isset($this->_registry)) {
+ $this->_registry = &$this->config->getRegistry();
+ }
+
+ $channel = $pkg->getChannel();
+ // {{{ assemble the destination paths
+ if (!in_array($atts['attribs']['role'],
+ PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) {
+ return $this->raiseError('Invalid role `' . $atts['attribs']['role'] .
+ "' for file $file");
+ }
+ $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config);
+ $err = $role->setup($this, $pkg, $atts['attribs'], $file);
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+ if (!$role->isInstallable()) {
+ return;
+ }
+ $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path);
+ if (PEAR::isError($info)) {
+ return $info;
+ } else {
+ list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info;
+ }
+ if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) {
+ return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED);
+ }
+ $final_dest_file = $installed_as = $dest_file;
+ if (isset($this->_options['packagingroot'])) {
+ $final_dest_file = $this->_prependPath($final_dest_file,
+ $this->_options['packagingroot']);
+ }
+ $dest_dir = dirname($final_dest_file);
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+ // }}}
+
+ if (empty($this->_options['register-only'])) {
+ if (!file_exists($dest_dir) || !is_dir($dest_dir)) {
+ if (!$this->mkDirHier($dest_dir)) {
+ return $this->raiseError("failed to mkdir $dest_dir",
+ PEAR_INSTALLER_FAILED);
+ }
+ $this->log(3, "+ mkdir $dest_dir");
+ }
+ }
+ $attribs = $atts['attribs'];
+ unset($atts['attribs']);
+ // pretty much nothing happens if we are only registering the install
+ if (empty($this->_options['register-only'])) {
+ if (!count($atts)) { // no tasks
+ if (!file_exists($orig_file)) {
+ return $this->raiseError("file $orig_file does not exist",
+ PEAR_INSTALLER_FAILED);
+ }
+ if (!@copy($orig_file, $dest_file)) {
+ return $this->raiseError("failed to write $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+ $this->log(3, "+ cp $orig_file $dest_file");
+ if (isset($attribs['md5sum'])) {
+ $md5sum = md5_file($dest_file);
+ }
+ } else { // file with tasks
+ if (!file_exists($orig_file)) {
+ return $this->raiseError("file $orig_file does not exist",
+ PEAR_INSTALLER_FAILED);
+ }
+ $contents = file_get_contents($orig_file);
+ if ($contents === false) {
+ $contents = '';
+ }
+ if (isset($attribs['md5sum'])) {
+ $md5sum = md5($contents);
+ }
+ foreach ($atts as $tag => $raw) {
+ $tag = str_replace(array($pkg->getTasksNs() . ':', '-'),
+ array('', '_'), $tag);
+ $task = "PEAR_Task_$tag";
+ $task = &new $task($this->config, $this, PEAR_TASK_INSTALL);
+ if (!$task->isScript()) { // scripts are only handled after installation
+ $task->init($raw, $attribs, $pkg->getLastInstalledVersion());
+ $res = $task->startSession($pkg, $contents, $final_dest_file);
+ if ($res === false) {
+ continue; // skip this file
+ }
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+ $contents = $res; // save changes
+ }
+ $wp = @fopen($dest_file, "wb");
+ if (!is_resource($wp)) {
+ return $this->raiseError("failed to create $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+ if (fwrite($wp, $contents) === false) {
+ return $this->raiseError("failed writing to $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+ fclose($wp);
+ }
+ }
+ // {{{ check the md5
+ if (isset($md5sum)) {
+ if (strtolower($md5sum) === strtolower($attribs['md5sum'])) {
+ $this->log(2, "md5sum ok: $final_dest_file");
+ } else {
+ if (empty($options['force'])) {
+ // delete the file
+ if (file_exists($dest_file)) {
+ unlink($dest_file);
+ }
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError("bad md5sum for file $final_dest_file",
+ PEAR_INSTALLER_FAILED);
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ }
+ }
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ }
+ }
+ }
+ } else {
+ $real_atts['attribs']['md5sum'] = md5_file($dest_file);
+ }
+ // }}}
+ // {{{ set file permissions
+ if (!OS_WINDOWS) {
+ if ($role->isExecutable()) {
+ $mode = 0777 & ~(int)octdec($this->config->get('umask'));
+ $this->log(3, "+ chmod +x $dest_file");
+ } else {
+ $mode = 0666 & ~(int)octdec($this->config->get('umask'));
+ }
+ if ($attribs['role'] != 'src') {
+ $this->addFileOperation("chmod", array($mode, $dest_file));
+ if (!@chmod($dest_file, $mode)) {
+ if (!isset($options['soft'])) {
+ $this->log(0, "failed to change mode of $dest_file: $php_errormsg");
+ }
+ }
+ }
+ }
+ // }}}
+ if ($attribs['role'] == 'src') {
+ rename($dest_file, $final_dest_file);
+ $this->log(2, "renamed source file $dest_file to $final_dest_file");
+ } else {
+ $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension()));
+ }
+ }
+ // Store the full path where the file was installed for easy uninstall
+ if ($attribs['role'] != 'src') {
+ $loc = $this->config->get($role->getLocationConfig(), null, $channel);
+ $this->addFileOperation("installed_as", array($file, $installed_as,
+ $loc,
+ dirname(substr($installed_as, strlen($loc)))));
+ }
+
+ //$this->log(2, "installed: $dest_file");
+ return PEAR_INSTALLER_OK;
+ }
+
+ // }}}
+ // {{{ addFileOperation()
+
+ /**
+ * Add a file operation to the current file transaction.
+ *
+ * @see startFileTransaction()
+ * @param string $type This can be one of:
+ * - rename: rename a file ($data has 3 values)
+ * - backup: backup an existing file ($data has 1 value)
+ * - removebackup: clean up backups created during install ($data has 1 value)
+ * - chmod: change permissions on a file ($data has 2 values)
+ * - delete: delete a file ($data has 1 value)
+ * - rmdir: delete a directory if empty ($data has 1 value)
+ * - installed_as: mark a file as installed ($data has 4 values).
+ * @param array $data For all file operations, this array must contain the
+ * full path to the file or directory that is being operated on. For
+ * the rename command, the first parameter must be the file to rename,
+ * the second its new name, the third whether this is a PHP extension.
+ *
+ * The installed_as operation contains 4 elements in this order:
+ * 1. Filename as listed in the filelist element from package.xml
+ * 2. Full path to the installed file
+ * 3. Full path from the php_dir configuration variable used in this
+ * installation
+ * 4. Relative path from the php_dir that this file is installed in
+ */
+ function addFileOperation($type, $data)
+ {
+ if (!is_array($data)) {
+ return $this->raiseError('Internal Error: $data in addFileOperation'
+ . ' must be an array, was ' . gettype($data));
+ }
+ if ($type == 'chmod') {
+ $octmode = decoct($data[0]);
+ $this->log(3, "adding to transaction: $type $octmode $data[1]");
+ } else {
+ $this->log(3, "adding to transaction: $type " . implode(" ", $data));
+ }
+ $this->file_operations[] = array($type, $data);
+ }
+
+ // }}}
+ // {{{ startFileTransaction()
+
+ function startFileTransaction($rollback_in_case = false)
+ {
+ if (count($this->file_operations) && $rollback_in_case) {
+ $this->rollbackFileTransaction();
+ }
+ $this->file_operations = array();
+ }
+
+ // }}}
+ // {{{ commitFileTransaction()
+
+ function commitFileTransaction()
+ {
+ $n = count($this->file_operations);
+ $this->log(2, "about to commit $n file operations");
+ // {{{ first, check permissions and such manually
+ $errors = array();
+ foreach ($this->file_operations as $tr) {
+ list($type, $data) = $tr;
+ switch ($type) {
+ case 'rename':
+ if (!file_exists($data[0])) {
+ $errors[] = "cannot rename file $data[0], doesn't exist";
+ }
+ // check that dest dir. is writable
+ if (!is_writable(dirname($data[1]))) {
+ $errors[] = "permission denied ($type): $data[1]";
+ }
+ break;
+ case 'chmod':
+ // check that file is writable
+ if (!is_writable($data[1])) {
+ $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]);
+ }
+ break;
+ case 'delete':
+ if (!file_exists($data[0])) {
+ $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted");
+ }
+ // check that directory is writable
+ if (file_exists($data[0])) {
+ if (!is_writable(dirname($data[0]))) {
+ $errors[] = "permission denied ($type): $data[0]";
+ } else {
+ // make sure the file to be deleted can be opened for writing
+ $fp = false;
+ if (!is_dir($data[0]) &&
+ (!is_writable($data[0]) || !($fp = @fopen($data[0], 'a')))) {
+ $errors[] = "permission denied ($type): $data[0]";
+ } elseif ($fp) {
+ fclose($fp);
+ }
+ }
+ }
+ break;
+ }
+
+ }
+ // }}}
+ $m = sizeof($errors);
+ if ($m > 0) {
+ foreach ($errors as $error) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(1, $error);
+ }
+ }
+ if (!isset($this->_options['ignore-errors'])) {
+ return false;
+ }
+ }
+ $this->_dirtree = array();
+ // {{{ really commit the transaction
+ foreach ($this->file_operations as $i => $tr) {
+ if (!$tr) {
+ // support removal of non-existing backups
+ continue;
+ }
+ list($type, $data) = $tr;
+ switch ($type) {
+ case 'backup':
+ if (!file_exists($data[0])) {
+ $this->file_operations[$i] = false;
+ break;
+ }
+ if (!@copy($data[0], $data[0] . '.bak')) {
+ $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] .
+ '.bak ' . $php_errormsg);
+ return false;
+ }
+ $this->log(3, "+ backup $data[0] to $data[0].bak");
+ break;
+ case 'removebackup':
+ if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) {
+ unlink($data[0] . '.bak');
+ $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
+ }
+ break;
+ case 'rename':
+ if (file_exists($data[1])) {
+ $test = @unlink($data[1]);
+ } else {
+ $test = null;
+ }
+ if (!$test && file_exists($data[1])) {
+ if ($data[2]) {
+ $extra = ', this extension must be installed manually. Rename to "' .
+ basename($data[1]) . '"';
+ } else {
+ $extra = '';
+ }
+ if (!isset($this->_options['soft'])) {
+ $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' .
+ $data[0] . $extra);
+ }
+ if (!isset($this->_options['ignore-errors'])) {
+ return false;
+ }
+ }
+ // permissions issues with rename - copy() is far superior
+ $perms = @fileperms($data[0]);
+ if (!@copy($data[0], $data[1])) {
+ $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] .
+ ' ' . $php_errormsg);
+ return false;
+ }
+ // copy over permissions, otherwise they are lost
+ @chmod($data[1], $perms);
+ @unlink($data[0]);
+ $this->log(3, "+ mv $data[0] $data[1]");
+ break;
+ case 'chmod':
+ if (!@chmod($data[1], $data[0])) {
+ $this->log(1, 'Could not chmod ' . $data[1] . ' to ' .
+ decoct($data[0]) . ' ' . $php_errormsg);
+ return false;
+ }
+ $octmode = decoct($data[0]);
+ $this->log(3, "+ chmod $octmode $data[1]");
+ break;
+ case 'delete':
+ if (file_exists($data[0])) {
+ if (!@unlink($data[0])) {
+ $this->log(1, 'Could not delete ' . $data[0] . ' ' .
+ $php_errormsg);
+ return false;
+ }
+ $this->log(3, "+ rm $data[0]");
+ }
+ break;
+ case 'rmdir':
+ if (file_exists($data[0])) {
+ do {
+ $testme = opendir($data[0]);
+ while (false !== ($entry = readdir($testme))) {
+ if ($entry == '.' || $entry == '..') {
+ continue;
+ }
+ closedir($testme);
+ break 2; // this directory is not empty and can't be
+ // deleted
+ }
+ closedir($testme);
+ if (!@rmdir($data[0])) {
+ $this->log(1, 'Could not rmdir ' . $data[0] . ' ' .
+ $php_errormsg);
+ return false;
+ }
+ $this->log(3, "+ rmdir $data[0]");
+ } while (false);
+ }
+ break;
+ case 'installed_as':
+ $this->pkginfo->setInstalledAs($data[0], $data[1]);
+ if (!isset($this->_dirtree[dirname($data[1])])) {
+ $this->_dirtree[dirname($data[1])] = true;
+ $this->pkginfo->setDirtree(dirname($data[1]));
+
+ while(!empty($data[3]) && dirname($data[3]) != $data[3] &&
+ $data[3] != '/' && $data[3] != '\\') {
+ $this->pkginfo->setDirtree($pp =
+ $this->_prependPath($data[3], $data[2]));
+ $this->_dirtree[$pp] = true;
+ $data[3] = dirname($data[3]);
+ }
+ }
+ break;
+ }
+ }
+ // }}}
+ $this->log(2, "successfully committed $n file operations");
+ $this->file_operations = array();
+ return true;
+ }
+
+ // }}}
+ // {{{ rollbackFileTransaction()
+
+ function rollbackFileTransaction()
+ {
+ $n = count($this->file_operations);
+ $this->log(2, "rolling back $n file operations");
+ foreach ($this->file_operations as $tr) {
+ list($type, $data) = $tr;
+ switch ($type) {
+ case 'backup':
+ if (file_exists($data[0] . '.bak')) {
+ if (file_exists($data[0] && is_writable($data[0]))) {
+ unlink($data[0]);
+ }
+ @copy($data[0] . '.bak', $data[0]);
+ $this->log(3, "+ restore $data[0] from $data[0].bak");
+ }
+ break;
+ case 'removebackup':
+ if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) {
+ unlink($data[0] . '.bak');
+ $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
+ }
+ break;
+ case 'rename':
+ @unlink($data[0]);
+ $this->log(3, "+ rm $data[0]");
+ break;
+ case 'mkdir':
+ @rmdir($data[0]);
+ $this->log(3, "+ rmdir $data[0]");
+ break;
+ case 'chmod':
+ break;
+ case 'delete':
+ break;
+ case 'installed_as':
+ $this->pkginfo->setInstalledAs($data[0], false);
+ break;
+ }
+ }
+ $this->pkginfo->resetDirtree();
+ $this->file_operations = array();
+ }
+
+ // }}}
+ // {{{ mkDirHier($dir)
+
+ function mkDirHier($dir)
+ {
+ $this->addFileOperation('mkdir', array($dir));
+ return parent::mkDirHier($dir);
+ }
+
+ // }}}
+ // {{{ download()
+
+ /**
+ * Download any files and their dependencies, if necessary
+ *
+ * @param array a mixed list of package names, local files, or package.xml
+ * @param PEAR_Config
+ * @param array options from the command line
+ * @param array this is the array that will be populated with packages to
+ * install. Format of each entry:
+ *
+ *
+ * array('pkg' => 'package_name', 'file' => '/path/to/local/file',
+ * 'info' => array() // parsed package.xml
+ * );
+ *
+ * @param array this will be populated with any error messages
+ * @param false private recursion variable
+ * @param false private recursion variable
+ * @param false private recursion variable
+ * @deprecated in favor of PEAR_Downloader
+ */
+ function download($packages, $options, &$config, &$installpackages,
+ &$errors, $installed = false, $willinstall = false, $state = false)
+ {
+ // trickiness: initialize here
+ parent::PEAR_Downloader($this->ui, $options, $config);
+ $ret = parent::download($packages);
+ $errors = $this->getErrorMsgs();
+ $installpackages = $this->getDownloadedPackages();
+ trigger_error("PEAR Warning: PEAR_Installer::download() is deprecated " .
+ "in favor of PEAR_Downloader class", E_USER_WARNING);
+ return $ret;
+ }
+
+ // }}}
+ // {{{ _parsePackageXml()
+
+ function _parsePackageXml(&$descfile, &$tmpdir)
+ {
+ if (substr($descfile, -4) == '.xml') {
+ $tmpdir = false;
+ } else {
+ // {{{ Decompress pack in tmp dir -------------------------------------
+
+ // To allow relative package file names
+ $descfile = realpath($descfile);
+
+ if (PEAR::isError($tmpdir = System::mktemp('-d'))) {
+ return $tmpdir;
+ }
+ $this->log(3, '+ tmp dir created at ' . $tmpdir);
+ // }}}
+ }
+ // Parse xml file -----------------------------------------------
+ $pkg = new PEAR_PackageFile($this->config, $this->debug, $tmpdir);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($p)) {
+ if (is_array($p->getUserInfo())) {
+ foreach ($p->getUserInfo() as $err) {
+ $loglevel = $err['level'] == 'error' ? 0 : 1;
+ if (!isset($this->_options['soft'])) {
+ $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']);
+ }
+ }
+ }
+ return $this->raiseError('Installation failed: invalid package file');
+ } else {
+ $descfile = $p->getPackageFile();
+ }
+ return $p;
+ }
+
+ // }}}
+ /**
+ * Set the list of PEAR_Downloader_Package objects to allow more sane
+ * dependency validation
+ * @param array
+ */
+ function setDownloadedPackages(&$pkgs)
+ {
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $this->analyzeDependencies($pkgs);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+ $this->_downloadedPackages = &$pkgs;
+ }
+
+ /**
+ * Set the list of PEAR_Downloader_Package objects to allow more sane
+ * dependency validation
+ * @param array
+ */
+ function setUninstallPackages(&$pkgs)
+ {
+ $this->_downloadedPackages = &$pkgs;
+ }
+
+ function getInstallPackages()
+ {
+ return $this->_downloadedPackages;
+ }
+
+ // {{{ install()
+
+ /**
+ * Installs the files within the package file specified.
+ *
+ * @param string|PEAR_Downloader_Package $pkgfile path to the package file,
+ * or a pre-initialized packagefile object
+ * @param array $options
+ * recognized options:
+ * - installroot : optional prefix directory for installation
+ * - force : force installation
+ * - register-only : update registry but don't install files
+ * - upgrade : upgrade existing install
+ * - soft : fail silently
+ * - nodeps : ignore dependency conflicts/missing dependencies
+ * - alldeps : install all dependencies
+ * - onlyreqdeps : install only required dependencies
+ *
+ * @return array|PEAR_Error package info if successful
+ */
+
+ function install($pkgfile, $options = array())
+ {
+ $this->_options = $options;
+ $this->_registry = &$this->config->getRegistry();
+ if (is_object($pkgfile)) {
+ $dlpkg = &$pkgfile;
+ $pkg = $pkgfile->getPackageFile();
+ $pkgfile = $pkg->getArchiveFile();
+ $descfile = $pkg->getPackageFile();
+ $tmpdir = dirname($descfile);
+ } else {
+ $descfile = $pkgfile;
+ $tmpdir = '';
+ if (PEAR::isError($pkg = &$this->_parsePackageXml($descfile, $tmpdir))) {
+ return $pkg;
+ }
+ }
+
+ if (realpath($descfile) != realpath($pkgfile)) {
+ $tar = new Archive_Tar($pkgfile);
+ if (!$tar->extract($tmpdir)) {
+ return $this->raiseError("unable to unpack $pkgfile");
+ }
+ }
+
+ $pkgname = $pkg->getName();
+ $channel = $pkg->getChannel();
+ if (isset($this->_options['packagingroot'])) {
+ $regdir = $this->_prependPath(
+ $this->config->get('php_dir', null, 'pear.php.net'),
+ $this->_options['packagingroot']);
+ $packrootphp_dir = $this->_prependPath(
+ $this->config->get('php_dir', null, $channel),
+ $this->_options['packagingroot']);
+ }
+
+ if (isset($options['installroot'])) {
+ $this->config->setInstallRoot($options['installroot']);
+ $this->_registry = &$this->config->getRegistry();
+ $installregistry = &$this->_registry;
+ $this->installroot = ''; // all done automagically now
+ $php_dir = $this->config->get('php_dir', null, $channel);
+ } else {
+ $this->config->setInstallRoot(false);
+ $this->_registry = &$this->config->getRegistry();
+ if (isset($this->_options['packagingroot'])) {
+ $installregistry = &new PEAR_Registry($regdir);
+ if (!$installregistry->channelExists($channel, true)) {
+ // we need to fake a channel-discover of this channel
+ $chanobj = $this->_registry->getChannel($channel, true);
+ $installregistry->addChannel($chanobj);
+ }
+ $php_dir = $packrootphp_dir;
+ } else {
+ $installregistry = &$this->_registry;
+ $php_dir = $this->config->get('php_dir', null, $channel);
+ }
+ $this->installroot = '';
+ }
+
+ // {{{ checks to do when not in "force" mode
+ if (empty($options['force']) &&
+ (file_exists($this->config->get('php_dir')) &&
+ is_dir($this->config->get('php_dir')))) {
+ $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname);
+ $instfilelist = $pkg->getInstallationFileList(true);
+ if (PEAR::isError($instfilelist)) {
+ return $instfilelist;
+ }
+ // ensure we have the most accurate registry
+ $installregistry->flushFileMap();
+ $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1');
+ if (PEAR::isError($test)) {
+ return $test;
+ }
+ if (sizeof($test)) {
+ $pkgs = $this->getInstallPackages();
+ $found = false;
+ foreach ($pkgs as $param) {
+ if ($pkg->isSubpackageOf($param)) {
+ $found = true;
+ break;
+ }
+ }
+ if ($found) {
+ // subpackages can conflict with earlier versions of parent packages
+ $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel());
+ $tmp = $test;
+ foreach ($tmp as $file => $info) {
+ if (is_array($info)) {
+ if (strtolower($info[1]) == strtolower($param->getPackage()) &&
+ strtolower($info[0]) == strtolower($param->getChannel())) {
+ unset($test[$file]);
+ unset($parentreg['filelist'][$file]);
+ }
+ } else {
+ if (strtolower($param->getChannel()) != 'pear.php.net') {
+ continue;
+ }
+ if (strtolower($info) == strtolower($param->getPackage())) {
+ unset($test[$file]);
+ unset($parentreg['filelist'][$file]);
+ }
+ }
+ }
+ $pfk = &new PEAR_PackageFile($this->config);
+ $parentpkg = &$pfk->fromArray($parentreg);
+ $installregistry->updatePackage2($parentpkg);
+ }
+ if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) {
+ $tmp = $test;
+ foreach ($tmp as $file => $info) {
+ if (is_string($info)) {
+ // pear.php.net packages are always stored as strings
+ if (strtolower($info) == strtolower($param->getPackage())) {
+ // upgrading existing package
+ unset($test[$file]);
+ }
+ }
+ }
+ }
+ if (sizeof($test)) {
+ $msg = "$channel/$pkgname: conflicting files found:\n";
+ $longest = max(array_map("strlen", array_keys($test)));
+ $fmt = "%${longest}s (%s)\n";
+ foreach ($test as $file => $info) {
+ if (!is_array($info)) {
+ $info = array('pear.php.net', $info);
+ }
+ $info = $info[0] . '/' . $info[1];
+ $msg .= sprintf($fmt, $file, $info);
+ }
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError($msg);
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "WARNING: $msg");
+ }
+ }
+ }
+ }
+ }
+ // }}}
+
+ $this->startFileTransaction();
+
+ if (empty($options['upgrade']) && empty($options['soft'])) {
+ // checks to do only when installing new packages
+ if ($channel == 'pecl.php.net') {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ if (!$test) {
+ $test = $installregistry->packageExists($pkgname, 'pear.php.net');
+ }
+ } else {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ }
+ if (empty($options['force']) && $test) {
+ return $this->raiseError("$channel/$pkgname is already installed");
+ }
+ } else {
+ $usechannel = $channel;
+ if ($channel == 'pecl.php.net') {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ if (!$test) {
+ $test = $installregistry->packageExists($pkgname, 'pear.php.net');
+ $usechannel = 'pear.php.net';
+ }
+ } else {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ }
+ if ($test) {
+ $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel);
+ $v2 = $pkg->getVersion();
+ $cmp = version_compare("$v1", "$v2", 'gt');
+ if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) {
+ return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)");
+ }
+ if (empty($options['register-only'])) {
+ // when upgrading, remove old release's files first:
+ if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel,
+ true))) {
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError($err);
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: ' . $err->getMessage());
+ }
+ }
+ } else {
+ $backedup = $err;
+ }
+ }
+ }
+ }
+
+ // {{{ Copy files to dest dir ---------------------------------------
+
+ // info from the package it self we want to access from _installFile
+ $this->pkginfo = &$pkg;
+ // used to determine whether we should build any C code
+ $this->source_files = 0;
+
+ $savechannel = $this->config->get('default_channel');
+ if (empty($options['register-only']) && !is_dir($php_dir)) {
+ if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) {
+ return $this->raiseError("no installation destination directory '$php_dir'\n");
+ }
+ }
+
+ $tmp_path = dirname($descfile);
+ if (substr($pkgfile, -4) != '.xml') {
+ $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion();
+ }
+
+ $this->configSet('default_channel', $channel);
+ // {{{ install files
+
+ $ver = $pkg->getPackagexmlVersion();
+ if (version_compare($ver, '2.0', '>=')) {
+ $filelist = $pkg->getInstallationFilelist();
+ } else {
+ $filelist = $pkg->getFileList();
+ }
+ if (PEAR::isError($filelist)) {
+ return $filelist;
+ }
+ $p = &$installregistry->getPackage($pkgname, $channel);
+ if (empty($options['register-only']) && $p) {
+ $dirtree = $p->getDirTree();
+ } else {
+ $dirtree = false;
+ }
+ $pkg->resetFilelist();
+ $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(),
+ 'version', $pkg->getChannel()));
+ foreach ($filelist as $file => $atts) {
+ if ($pkg->getPackagexmlVersion() == '1.0') {
+ $this->expectError(PEAR_INSTALLER_FAILED);
+ $res = $this->_installFile($file, $atts, $tmp_path, $options);
+ $this->popExpect();
+ } else {
+ $this->expectError(PEAR_INSTALLER_FAILED);
+ $res = $this->_installFile2($pkg, $file, $atts, $tmp_path, $options);
+ $this->popExpect();
+ }
+ if (PEAR::isError($res)) {
+ if (empty($options['ignore-errors'])) {
+ $this->rollbackFileTransaction();
+ if ($res->getMessage() == "file does not exist") {
+ $this->raiseError("file $file in package.xml does not exist");
+ }
+ return $this->raiseError($res);
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "Warning: " . $res->getMessage());
+ }
+ }
+ }
+ $real = isset($atts['attribs']) ? $atts['attribs'] : $atts;
+ if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') {
+ // Register files that were installed
+ $pkg->installedFile($file, $atts);
+ }
+ }
+ // }}}
+
+ // {{{ compile and install source files
+ if ($this->source_files > 0 && empty($options['nobuild'])) {
+ if (PEAR::isError($err =
+ $this->_compileSourceFiles($savechannel, $pkg))) {
+ return $err;
+ }
+ }
+ // }}}
+
+ if (isset($backedup)) {
+ $this->_removeBackups($backedup);
+ }
+ if (!$this->commitFileTransaction()) {
+ $this->rollbackFileTransaction();
+ $this->configSet('default_channel', $savechannel);
+ return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED);
+ }
+ // }}}
+
+ $ret = false;
+ $installphase = 'install';
+ $oldversion = false;
+ // {{{ Register that the package is installed -----------------------
+ if (empty($options['upgrade'])) {
+ // if 'force' is used, replace the info in registry
+ $usechannel = $channel;
+ if ($channel == 'pecl.php.net') {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ if (!$test) {
+ $test = $installregistry->packageExists($pkgname, 'pear.php.net');
+ $usechannel = 'pear.php.net';
+ }
+ } else {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ }
+ if (!empty($options['force']) && $test) {
+ $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel);
+ $installregistry->deletePackage($pkgname, $usechannel);
+ }
+ $ret = $installregistry->addPackage2($pkg);
+ } else {
+ if ($dirtree) {
+ $this->startFileTransaction();
+ // attempt to delete empty directories
+ uksort($dirtree, array($this, '_sortDirs'));
+ foreach($dirtree as $dir => $notused) {
+ $this->addFileOperation('rmdir', array($dir));
+ }
+ $this->commitFileTransaction();
+ }
+ $usechannel = $channel;
+ if ($channel == 'pecl.php.net') {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ if (!$test) {
+ $test = $installregistry->packageExists($pkgname, 'pear.php.net');
+ $usechannel = 'pear.php.net';
+ }
+ } else {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ }
+ // new: upgrade installs a package if it isn't installed
+ if (!$test) {
+ $ret = $installregistry->addPackage2($pkg);
+ } else {
+ if ($usechannel != $channel) {
+ $installregistry->deletePackage($pkgname, $usechannel);
+ $ret = $installregistry->addPackage2($pkg);
+ } else {
+ $ret = $installregistry->updatePackage2($pkg);
+ }
+ $installphase = 'upgrade';
+ }
+ }
+ if (!$ret) {
+ $this->configSet('default_channel', $savechannel);
+ return $this->raiseError("Adding package $channel/$pkgname to registry failed");
+ }
+ // }}}
+ $this->configSet('default_channel', $savechannel);
+ if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist
+ if (PEAR_Task_Common::hasPostinstallTasks()) {
+ PEAR_Task_Common::runPostinstallTasks($installphase);
+ }
+ }
+ return $pkg->toArray(true);
+ }
+
+ // }}}
+
+ // {{{ _compileSourceFiles()
+ /**
+ * @param string
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ */
+ function _compileSourceFiles($savechannel, &$filelist)
+ {
+ require_once 'PEAR/Builder.php';
+ $this->log(1, "$this->source_files source files, building");
+ $bob = &new PEAR_Builder($this->ui);
+ $bob->debug = $this->debug;
+ $built = $bob->build($filelist, array(&$this, '_buildCallback'));
+ if (PEAR::isError($built)) {
+ $this->rollbackFileTransaction();
+ $this->configSet('default_channel', $savechannel);
+ return $built;
+ }
+ $this->log(1, "\nBuild process completed successfully");
+ foreach ($built as $ext) {
+ $bn = basename($ext['file']);
+ list($_ext_name, $_ext_suff) = explode('.', $bn);
+ if ($_ext_suff == '.so' || $_ext_suff == '.dll') {
+ if (extension_loaded($_ext_name)) {
+ $this->raiseError("Extension '$_ext_name' already loaded. " .
+ 'Please unload it in your php.ini file ' .
+ 'prior to install or upgrade');
+ }
+ $role = 'ext';
+ } else {
+ $role = 'src';
+ }
+ $dest = $ext['dest'];
+ $packagingroot = '';
+ if (isset($this->_options['packagingroot'])) {
+ $packagingroot = $this->_options['packagingroot'];
+ }
+ $copyto = $this->_prependPath($dest, $packagingroot);
+ if ($copyto != $dest) {
+ $this->log(1, "Installing '$dest' as '$copyto'");
+ } else {
+ $this->log(1, "Installing '$dest'");
+ }
+ $copydir = dirname($copyto);
+ // pretty much nothing happens if we are only registering the install
+ if (empty($this->_options['register-only'])) {
+ if (!file_exists($copydir) || !is_dir($copydir)) {
+ if (!$this->mkDirHier($copydir)) {
+ return $this->raiseError("failed to mkdir $copydir",
+ PEAR_INSTALLER_FAILED);
+ }
+ $this->log(3, "+ mkdir $copydir");
+ }
+ if (!@copy($ext['file'], $copyto)) {
+ return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED);
+ }
+ $this->log(3, "+ cp $ext[file] $copyto");
+ $this->addFileOperation('rename', array($ext['file'], $copyto));
+ if (!OS_WINDOWS) {
+ $mode = 0666 & ~(int)octdec($this->config->get('umask'));
+ $this->addFileOperation('chmod', array($mode, $copyto));
+ if (!@chmod($copyto, $mode)) {
+ $this->log(0, "failed to change mode of $copyto ($php_errormsg)");
+ }
+ }
+ }
+
+ if ($filelist->getPackageXmlVersion() == '1.0') {
+ $filelist->installedFile($bn, array(
+ 'role' => $role,
+ 'name' => $bn,
+ 'installed_as' => $dest,
+ 'php_api' => $ext['php_api'],
+ 'zend_mod_api' => $ext['zend_mod_api'],
+ 'zend_ext_api' => $ext['zend_ext_api'],
+ ));
+ } else {
+ $filelist->installedFile($bn, array('attribs' => array(
+ 'role' => $role,
+ 'name' => $bn,
+ 'installed_as' => $dest,
+ 'php_api' => $ext['php_api'],
+ 'zend_mod_api' => $ext['zend_mod_api'],
+ 'zend_ext_api' => $ext['zend_ext_api'],
+ )));
+ }
+ }
+ }
+
+ // }}}
+ function &getUninstallPackages()
+ {
+ return $this->_downloadedPackages;
+ }
+ // {{{ uninstall()
+
+ /**
+ * Uninstall a package
+ *
+ * This method removes all files installed by the application, and then
+ * removes any empty directories.
+ * @param string package name
+ * @param array Command-line options. Possibilities include:
+ *
+ * - installroot: base installation dir, if not the default
+ * - register-only : update registry but don't remove files
+ * - nodeps: do not process dependencies of other packages to ensure
+ * uninstallation does not break things
+ */
+ function uninstall($package, $options = array())
+ {
+ if (isset($options['installroot'])) {
+ $this->config->setInstallRoot($options['installroot']);
+ $this->installroot = '';
+ } else {
+ $this->config->setInstallRoot('');
+ $this->installroot = '';
+ }
+ $this->_registry = &$this->config->getRegistry();
+ if (is_object($package)) {
+ $channel = $package->getChannel();
+ $pkg = $package;
+ $package = $pkg->getPackage();
+ } else {
+ $pkg = false;
+ $info = $this->_registry->parsePackageName($package,
+ $this->config->get('default_channel'));
+ $channel = $info['channel'];
+ $package = $info['package'];
+ }
+ $savechannel = $this->config->get('default_channel');
+ $this->configSet('default_channel', $channel);
+ if (!is_object($pkg)) {
+ $pkg = $this->_registry->getPackage($package, $channel);
+ }
+ if (!$pkg) {
+ $this->configSet('default_channel', $savechannel);
+ return $this->raiseError($this->_registry->parsedPackageNameToString(
+ array(
+ 'channel' => $channel,
+ 'package' => $package
+ ), true) . ' not installed');
+ }
+ if ($pkg->getInstalledBinary()) {
+ // this is just an alias for a binary package
+ return $this->_registry->deletePackage($package, $channel);
+ }
+ $filelist = $pkg->getFilelist();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ if (!class_exists('PEAR_Dependency2')) {
+ require_once 'PEAR/Dependency2.php';
+ }
+ $depchecker = &new PEAR_Dependency2($this->config, $options,
+ array('channel' => $channel, 'package' => $package),
+ PEAR_VALIDATE_UNINSTALLING);
+ $e = $depchecker->validatePackageUninstall($this);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($e)) {
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError($e);
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: ' . $e->getMessage());
+ }
+ }
+ } elseif (is_array($e)) {
+ if (!isset($options['soft'])) {
+ $this->log(0, $e[0]);
+ }
+ }
+ $this->pkginfo = &$pkg;
+ // pretty much nothing happens if we are only registering the uninstall
+ if (empty($options['register-only'])) {
+ // {{{ Delete the files
+ $this->startFileTransaction();
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) {
+ PEAR::popErrorHandling();
+ $this->rollbackFileTransaction();
+ $this->configSet('default_channel', $savechannel);
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError($err);
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: ' . $err->getMessage());
+ }
+ }
+ } else {
+ PEAR::popErrorHandling();
+ }
+ if (!$this->commitFileTransaction()) {
+ $this->rollbackFileTransaction();
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError("uninstall failed");
+ } elseif (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: uninstall failed');
+ }
+ } else {
+ $this->startFileTransaction();
+ if ($dirtree = $pkg->getDirTree()) {
+ // attempt to delete empty directories
+ uksort($dirtree, array($this, '_sortDirs'));
+ foreach($dirtree as $dir => $notused) {
+ $this->addFileOperation('rmdir', array($dir));
+ }
+ } else {
+ $this->configSet('default_channel', $savechannel);
+ return $this->_registry->deletePackage($package, $channel);
+ }
+ if (!$this->commitFileTransaction()) {
+ $this->rollbackFileTransaction();
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError("uninstall failed");
+ } elseif (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: uninstall failed');
+ }
+ }
+ }
+ // }}}
+ }
+
+ $this->configSet('default_channel', $savechannel);
+ // Register that the package is no longer installed
+ return $this->_registry->deletePackage($package, $channel);
+ }
+
+ /**
+ * Sort a list of arrays of array(downloaded packagefilename) by dependency.
+ *
+ * It also removes duplicate dependencies
+ * @param array an array of PEAR_PackageFile_v[1/2] objects
+ * @return array|PEAR_Error array of array(packagefilename, package.xml contents)
+ */
+ function sortPackagesForUninstall(&$packages)
+ {
+ $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config);
+ if (PEAR::isError($this->_dependencyDB)) {
+ return $this->_dependencyDB;
+ }
+ usort($packages, array(&$this, '_sortUninstall'));
+ }
+
+ function _sortUninstall($a, $b)
+ {
+ if (!$a->getDeps() && !$b->getDeps()) {
+ return 0; // neither package has dependencies, order is insignificant
+ }
+ if ($a->getDeps() && !$b->getDeps()) {
+ return -1; // $a must be installed after $b because $a has dependencies
+ }
+ if (!$a->getDeps() && $b->getDeps()) {
+ return 1; // $b must be installed after $a because $b has dependencies
+ }
+ // both packages have dependencies
+ if ($this->_dependencyDB->dependsOn($a, $b)) {
+ return -1;
+ }
+ if ($this->_dependencyDB->dependsOn($b, $a)) {
+ return 1;
+ }
+ return 0;
+ }
+
+ // }}}
+ // {{{ _sortDirs()
+ function _sortDirs($a, $b)
+ {
+ if (strnatcmp($a, $b) == -1) return 1;
+ if (strnatcmp($a, $b) == 1) return -1;
+ return 0;
+ }
+
+ // }}}
+
+ // {{{ _buildCallback()
+
+ function _buildCallback($what, $data)
+ {
+ if (($what == 'cmdoutput' && $this->debug > 1) ||
+ ($what == 'output' && $this->debug > 0)) {
+ $this->ui->outputData(rtrim($data), 'build');
+ }
+ }
+
+ // }}}
+}
+
+// {{{ md5_file() utility function
+if (!function_exists("md5_file")) {
+ function md5_file($filename) {
+ if (!$fd = @fopen($file, 'r')) {
+ return false;
+ }
+ fclose($fd);
+ return md5(file_get_contents($filename));
+ }
+}
+// }}}
+
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role.php b/vendor/library/Excel/phpxls/PEAR/Installer/Role.php
new file mode 100644
index 0000000..5b77b5d
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role.php
@@ -0,0 +1,253 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Role.php,v 1.20 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * base class for installer roles
+ */
+require_once 'PEAR/Installer/Role/Common.php';
+require_once 'PEAR/XMLParser.php';
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role
+{
+ /**
+ * Set up any additional configuration variables that file roles require
+ *
+ * Never call this directly, it is called by the PEAR_Config constructor
+ * @param PEAR_Config
+ * @access private
+ * @static
+ */
+ static function initializeConfig(&$config)
+ {
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+ PEAR_Installer_Role::registerRoles();
+ }
+ foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) {
+ if (!$info['config_vars']) {
+ continue;
+ }
+ $config->_addConfigVars($class, $info['config_vars']);
+ }
+ }
+
+ /**
+ * @param PEAR_PackageFile_v2
+ * @param string role name
+ * @param PEAR_Config
+ * @return PEAR_Installer_Role_Common
+ * @static
+ */
+ static function &factory($pkg, $role, &$config)
+ {
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+ PEAR_Installer_Role::registerRoles();
+ }
+ if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) {
+ $a = false;
+ return $a;
+ }
+ $a = 'PEAR_Installer_Role_' . ucfirst($role);
+ if (!class_exists($a)) {
+ require_once str_replace('_', '/', $a) . '.php';
+ }
+ $b = new $a($config);
+ return $b;
+ }
+
+ /**
+ * Get a list of file roles that are valid for the particular release type.
+ *
+ * For instance, src files serve no purpose in regular php releases.
+ * @param string
+ * @param bool clear cache
+ * @return array
+ * @static
+ */
+ static function getValidRoles($release, $clear = false)
+ {
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+ PEAR_Installer_Role::registerRoles();
+ }
+ static $ret = array();
+ if ($clear) {
+ $ret = array();
+ }
+ if (isset($ret[$release])) {
+ return $ret[$release];
+ }
+ $ret[$release] = array();
+ foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
+ if (in_array($release, $okreleases['releasetypes'])) {
+ $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
+ }
+ }
+ return $ret[$release];
+ }
+
+ /**
+ * Get a list of roles that require their files to be installed
+ *
+ * Most roles must be installed, but src and package roles, for instance
+ * are pseudo-roles. src files are compiled into a new extension. Package
+ * roles are actually fully bundled releases of a package
+ * @param bool clear cache
+ * @return array
+ * @static
+ */
+ static function getInstallableRoles($clear = false)
+ {
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+ PEAR_Installer_Role::registerRoles();
+ }
+ static $ret;
+ if ($clear) {
+ unset($ret);
+ }
+ if (!isset($ret)) {
+ $ret = array();
+ foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
+ if ($okreleases['installable']) {
+ $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
+ }
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * Return an array of roles that are affected by the baseinstalldir attribute
+ *
+ * Most roles ignore this attribute, and instead install directly into:
+ * PackageName/filepath
+ * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php
+ * @param bool clear cache
+ * @return array
+ * @static
+ */
+ static function getBaseinstallRoles($clear = false)
+ {
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+ PEAR_Installer_Role::registerRoles();
+ }
+ static $ret;
+ if ($clear) {
+ unset($ret);
+ }
+ if (!isset($ret)) {
+ $ret = array();
+ foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
+ if ($okreleases['honorsbaseinstall']) {
+ $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
+ }
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * Return an array of file roles that should be analyzed for PHP content at package time,
+ * like the "php" role.
+ * @param bool clear cache
+ * @return array
+ * @static
+ */
+ static function getPhpRoles($clear = false)
+ {
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+ PEAR_Installer_Role::registerRoles();
+ }
+ static $ret;
+ if ($clear) {
+ unset($ret);
+ }
+ if (!isset($ret)) {
+ $ret = array();
+ foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
+ if ($okreleases['phpfile']) {
+ $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
+ }
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * Scan through the Command directory looking for classes
+ * and see what commands they implement.
+ * @param string which directory to look for classes, defaults to
+ * the Installer/Roles subdirectory of
+ * the directory from where this file (__FILE__) is
+ * included.
+ *
+ * @return bool TRUE on success, a PEAR error on failure
+ * @access public
+ * @static
+ */
+ static function registerRoles($dir = null)
+ {
+ $GLOBALS['_PEAR_INSTALLER_ROLES'] = array();
+ $parser = new PEAR_XMLParser;
+ if ($dir === null) {
+ $dir = dirname(__FILE__) . '/Role';
+ }
+ if (!file_exists($dir) || !is_dir($dir)) {
+ return PEAR::raiseError("registerRoles: opendir($dir) failed: does not exist/is not directory");
+ }
+ $dp = @opendir($dir);
+ if (empty($dp)) {
+ return PEAR::raiseError("registerRoles: opendir($dir) failed: $php_errmsg");
+ }
+ while ($entry = readdir($dp)) {
+ if ($entry{0} == '.' || substr($entry, -4) != '.xml') {
+ continue;
+ }
+ $class = "PEAR_Installer_Role_".substr($entry, 0, -4);
+ // List of roles
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) {
+ $file = "$dir/$entry";
+ $parser->parse(file_get_contents($file));
+ $data = $parser->getData();
+ if (!is_array($data['releasetypes'])) {
+ $data['releasetypes'] = array($data['releasetypes']);
+ }
+ $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data;
+ }
+ }
+ closedir($dp);
+ ksort($GLOBALS['_PEAR_INSTALLER_ROLES']);
+ PEAR_Installer_Role::getBaseinstallRoles(true);
+ PEAR_Installer_Role::getInstallableRoles(true);
+ PEAR_Installer_Role::getPhpRoles(true);
+ PEAR_Installer_Role::getValidRoles('****', true);
+ return true;
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Cfg.php b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Cfg.php
new file mode 100644
index 0000000..1928f60
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Cfg.php
@@ -0,0 +1,108 @@
+
+ * @copyright 2007-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Cfg.php,v 1.8 2008/05/14 21:26:30 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.7.0
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 2007-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.7.0
+ */
+class PEAR_Installer_Role_Cfg extends PEAR_Installer_Role_Common
+{
+ /**
+ * @var PEAR_Installer
+ */
+ var $installer;
+ /**
+ * the md5 of the original file
+ *
+ * @var unknown_type
+ */
+ var $md5 = null;
+ /**
+ * Do any unusual setup here
+ * @param PEAR_Installer
+ * @param PEAR_PackageFile_v2
+ * @param array file attributes
+ * @param string file name
+ */
+ function setup(&$installer, $pkg, $atts, $file)
+ {
+ $this->installer = &$installer;
+ $reg = &$this->installer->config->getRegistry();
+ $package = $reg->getPackage($pkg->getPackage(), $pkg->getChannel());
+ if ($package) {
+ $filelist = $package->getFilelist();
+ if (isset($filelist[$file]) && isset($filelist[$file]['md5sum'])) {
+ $this->md5 = $filelist[$file]['md5sum'];
+ }
+ }
+ }
+
+ function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null)
+ {
+ $test = parent::processInstallation($pkg, $atts, $file, $tmp_path, $layer);
+ if (@file_exists($test[2]) && @file_exists($test[3])) {
+ $md5 = md5_file($test[2]);
+ // configuration has already been installed, check for mods
+ if ($md5 !== $this->md5 && $md5 !== md5_file($test[3])) {
+ // configuration has been modified, so save our version as
+ // configfile-version
+ $old = $test[2];
+ $test[2] .= '.new-' . $pkg->getVersion();
+ // backup original and re-install it
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $tmpcfg = $this->config->get('temp_dir');
+ $newloc = System::mkdir(array('-p', $tmpcfg));
+ if (!$newloc) {
+ // try temp_dir
+ $newloc = System::mktemp(array('-d'));
+ if (!$newloc || PEAR::isError($newloc)) {
+ PEAR::popErrorHandling();
+ return PEAR::raiseError('Could not save existing configuration file '.
+ $old . ', unable to install. Please set temp_dir ' .
+ 'configuration variable to a writeable location and try again');
+ }
+ } else {
+ $newloc = $tmpcfg;
+ }
+ $temp_file = $newloc . DIRECTORY_SEPARATOR . uniqid('savefile');
+ if (!@copy($old, $temp_file)) {
+ PEAR::popErrorHandling();
+ return PEAR::raiseError('Could not save existing configuration file '.
+ $old . ', unable to install. Please set temp_dir ' .
+ 'configuration variable to a writeable location and try again');
+ }
+ PEAR::popErrorHandling();
+ $this->installer->log(0, "WARNING: configuration file $old is being installed as $test[2], you should manually merge in changes to the existing configuration file");
+ $this->installer->addFileOperation('rename', array($temp_file, $old, false));
+ $this->installer->addFileOperation('delete', array($temp_file));
+ }
+ }
+ return $test;
+ }
+}
+?>
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Cfg.xml b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Cfg.xml
new file mode 100644
index 0000000..7a415dc
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Cfg.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ cfg_dir
+
+ 1
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Common.php b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Common.php
new file mode 100644
index 0000000..32cd821
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Common.php
@@ -0,0 +1,180 @@
+
+ * @copyright 1997-2006 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Common.php,v 1.12 2006/10/19 23:55:32 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * Base class for all installation roles.
+ *
+ * This class allows extensibility of file roles. Packages with complex
+ * customization can now provide custom file roles along with the possibility of
+ * adding configuration values to match.
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2006 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Common
+{
+ /**
+ * @var PEAR_Config
+ * @access protected
+ */
+ var $config;
+
+ /**
+ * @param PEAR_Config
+ */
+ function PEAR_Installer_Role_Common(&$config)
+ {
+ $this->config = $config;
+ }
+
+ /**
+ * Retrieve configuration information about a file role from its XML info
+ *
+ * @param string $role Role Classname, as in "PEAR_Installer_Role_Data"
+ * @return array
+ */
+ function getInfo($role)
+ {
+ if (empty($GLOBALS['_PEAR_INSTALLER_ROLES'][$role])) {
+ return PEAR::raiseError('Unknown Role class: "' . $role . '"');
+ }
+ return $GLOBALS['_PEAR_INSTALLER_ROLES'][$role];
+ }
+
+ /**
+ * This is called for each file to set up the directories and files
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @param array attributes from the tag
+ * @param string file name
+ * @return array an array consisting of:
+ *
+ * 1 the original, pre-baseinstalldir installation directory
+ * 2 the final installation directory
+ * 3 the full path to the final location of the file
+ * 4 the location of the pre-installation file
+ */
+ function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null)
+ {
+ $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
+ ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+ if (PEAR::isError($roleInfo)) {
+ return $roleInfo;
+ }
+ if (!$roleInfo['locationconfig']) {
+ return false;
+ }
+ if ($roleInfo['honorsbaseinstall']) {
+ $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], $layer,
+ $pkg->getChannel());
+ if (!empty($atts['baseinstalldir'])) {
+ $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
+ }
+ } elseif ($roleInfo['unusualbaseinstall']) {
+ $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'],
+ $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage();
+ if (!empty($atts['baseinstalldir'])) {
+ $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
+ }
+ } else {
+ $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'],
+ $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage();
+ }
+ if (dirname($file) != '.' && empty($atts['install-as'])) {
+ $dest_dir .= DIRECTORY_SEPARATOR . dirname($file);
+ }
+ if (empty($atts['install-as'])) {
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file);
+ } else {
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as'];
+ }
+ $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file;
+
+ // Clean up the DIRECTORY_SEPARATOR mess
+ $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
+
+ list($dest_dir, $dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
+ array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR),
+ array($dest_dir, $dest_file, $orig_file));
+ return array($save_destdir, $dest_dir, $dest_file, $orig_file);
+ }
+
+ /**
+ * Get the name of the configuration variable that specifies the location of this file
+ * @return string|false
+ */
+ function getLocationConfig()
+ {
+ $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
+ ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+ if (PEAR::isError($roleInfo)) {
+ return $roleInfo;
+ }
+ return $roleInfo['locationconfig'];
+ }
+
+ /**
+ * Do any unusual setup here
+ * @param PEAR_Installer
+ * @param PEAR_PackageFile_v2
+ * @param array file attributes
+ * @param string file name
+ */
+ function setup(&$installer, $pkg, $atts, $file)
+ {
+ }
+
+ function isExecutable()
+ {
+ $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
+ ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+ if (PEAR::isError($roleInfo)) {
+ return $roleInfo;
+ }
+ return $roleInfo['executable'];
+ }
+
+ function isInstallable()
+ {
+ $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
+ ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+ if (PEAR::isError($roleInfo)) {
+ return $roleInfo;
+ }
+ return $roleInfo['installable'];
+ }
+
+ function isExtension()
+ {
+ $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
+ ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+ if (PEAR::isError($roleInfo)) {
+ return $roleInfo;
+ }
+ return $roleInfo['phpextension'];
+ }
+}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Data.php b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Data.php
new file mode 100644
index 0000000..394f68c
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Data.php
@@ -0,0 +1,34 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Data.php,v 1.7 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Data.xml b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Data.xml
new file mode 100644
index 0000000..eae6372
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Data.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ data_dir
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Doc.php b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Doc.php
new file mode 100644
index 0000000..b974dc6
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Doc.php
@@ -0,0 +1,34 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Doc.php,v 1.7 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Doc.xml b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Doc.xml
new file mode 100644
index 0000000..173afba
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Doc.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ doc_dir
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Ext.php b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Ext.php
new file mode 100644
index 0000000..38c0e9a
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Ext.php
@@ -0,0 +1,34 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Ext.php,v 1.7 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Ext extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Ext.xml b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Ext.xml
new file mode 100644
index 0000000..e2940fe
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Ext.xml
@@ -0,0 +1,12 @@
+
+ extbin
+ zendextbin
+ 1
+ ext_dir
+ 1
+
+
+
+ 1
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Php.php b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Php.php
new file mode 100644
index 0000000..f232b72
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Php.php
@@ -0,0 +1,34 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Php.php,v 1.8 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Php.xml b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Php.xml
new file mode 100644
index 0000000..6b9a0e6
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Php.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ php_dir
+ 1
+
+ 1
+
+
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Script.php b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Script.php
new file mode 100644
index 0000000..b8affdb
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Script.php
@@ -0,0 +1,34 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Script.php,v 1.7 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Script.xml b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Script.xml
new file mode 100644
index 0000000..e732cf2
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Script.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ bin_dir
+ 1
+
+
+ 1
+
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Src.php b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Src.php
new file mode 100644
index 0000000..68d07e4
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Src.php
@@ -0,0 +1,40 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Src.php,v 1.7 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Src extends PEAR_Installer_Role_Common
+{
+ function setup(&$installer, $pkg, $atts, $file)
+ {
+ $installer->source_files++;
+ }
+}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Src.xml b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Src.xml
new file mode 100644
index 0000000..1034834
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Src.xml
@@ -0,0 +1,12 @@
+
+ extsrc
+ zendextsrc
+ 1
+ temp_dir
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Test.php b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Test.php
new file mode 100644
index 0000000..63979b9
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Test.php
@@ -0,0 +1,34 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Test.php,v 1.7 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Test.xml b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Test.xml
new file mode 100644
index 0000000..51d5b89
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Test.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ test_dir
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Www.php b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Www.php
new file mode 100644
index 0000000..801097f
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Www.php
@@ -0,0 +1,34 @@
+
+ * @copyright 2007-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Www.php,v 1.2 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.7.0
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 2007-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.7.0
+ */
+class PEAR_Installer_Role_Www extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/Installer/Role/Www.xml b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Www.xml
new file mode 100644
index 0000000..7598be3
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/Installer/Role/Www.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ www_dir
+ 1
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/PackageFile.php b/vendor/library/Excel/phpxls/PEAR/PackageFile.php
new file mode 100644
index 0000000..0dc42e9
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/PackageFile.php
@@ -0,0 +1,474 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: PackageFile.php,v 1.41 2008/01/03 20:26:36 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * needed for PEAR_VALIDATE_* constants
+ */
+require_once 'PEAR/Validate.php';
+/**
+ * Error code if the package.xml tag does not contain a valid version
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1);
+/**
+ * Error code if the package.xml tag version is not supported (version 1.0 and 1.1 are the only supported versions,
+ * currently
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2);
+/**
+ * Abstraction for the package.xml package description file
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile
+{
+ /**
+ * @var PEAR_Config
+ */
+ var $_config;
+ var $_debug;
+ /**
+ * Temp directory for uncompressing tgz files.
+ * @var string|false
+ */
+ var $_tmpdir;
+ var $_logger = false;
+ /**
+ * @var boolean
+ */
+ var $_rawReturn = false;
+
+ /**
+ *
+ * @param PEAR_Config $config
+ * @param ? $debug
+ * @param string @tmpdir Optional temporary directory for uncompressing
+ * files
+ */
+ function PEAR_PackageFile(&$config, $debug = false, $tmpdir = false)
+ {
+ $this->_config = $config;
+ $this->_debug = $debug;
+ $this->_tmpdir = $tmpdir;
+ }
+
+ /**
+ * Turn off validation - return a parsed package.xml without checking it
+ *
+ * This is used by the package-validate command
+ */
+ function rawReturn()
+ {
+ $this->_rawReturn = true;
+ }
+
+ function setLogger(&$l)
+ {
+ $this->_logger = &$l;
+ }
+
+ /**
+ * Create a PEAR_PackageFile_Parser_v* of a given version.
+ * @param int $version
+ * @return PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1
+ */
+ function &parserFactory($version)
+ {
+ if (!in_array($version{0}, array('1', '2'))) {
+ $a = false;
+ return $a;
+ }
+ include_once 'PEAR/PackageFile/Parser/v' . $version{0} . '.php';
+ $version = $version{0};
+ $class = "PEAR_PackageFile_Parser_v$version";
+ $a = new $class;
+ return $a;
+ }
+
+ /**
+ * For simpler unit-testing
+ * @return string
+ */
+ function getClassPrefix()
+ {
+ return 'PEAR_PackageFile_v';
+ }
+
+ /**
+ * Create a PEAR_PackageFile_v* of a given version.
+ * @param int $version
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v1
+ */
+ function &factory($version)
+ {
+ if (!in_array($version{0}, array('1', '2'))) {
+ $a = false;
+ return $a;
+ }
+ include_once 'PEAR/PackageFile/v' . $version{0} . '.php';
+ $version = $version{0};
+ $class = $this->getClassPrefix() . $version;
+ $a = new $class;
+ return $a;
+ }
+
+ /**
+ * Create a PEAR_PackageFile_v* from its toArray() method
+ *
+ * WARNING: no validation is performed, the array is assumed to be valid,
+ * always parse from xml if you want validation.
+ * @param array $arr
+ * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2
+ * @uses factory() to construct the returned object.
+ */
+ function &fromArray($arr)
+ {
+ if (isset($arr['xsdversion'])) {
+ $obj = &$this->factory($arr['xsdversion']);
+ if ($this->_logger) {
+ $obj->setLogger($this->_logger);
+ }
+ $obj->setConfig($this->_config);
+ $obj->fromArray($arr);
+ return $obj;
+ } else {
+ if (isset($arr['package']['attribs']['version'])) {
+ $obj = &$this->factory($arr['package']['attribs']['version']);
+ } else {
+ $obj = &$this->factory('1.0');
+ }
+ if ($this->_logger) {
+ $obj->setLogger($this->_logger);
+ }
+ $obj->setConfig($this->_config);
+ $obj->fromArray($arr);
+ return $obj;
+ }
+ }
+
+ /**
+ * Create a PEAR_PackageFile_v* from an XML string.
+ * @access public
+ * @param string $data contents of package.xml file
+ * @param int $state package state (one of PEAR_VALIDATE_* constants)
+ * @param string $file full path to the package.xml file (and the files
+ * it references)
+ * @param string $archive optional name of the archive that the XML was
+ * extracted from, if any
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @uses parserFactory() to construct a parser to load the package.
+ */
+ function &fromXmlString($data, $state, $file, $archive = false)
+ {
+ if (preg_match('/]+version="([0-9]+\.[0-9]+)"/', $data, $packageversion)) {
+ if (!in_array($packageversion[1], array('1.0', '2.0', '2.1'))) {
+ return PEAR::raiseError('package.xml version "' . $packageversion[1] .
+ '" is not supported, only 1.0, 2.0, and 2.1 are supported.');
+ }
+ $object = &$this->parserFactory($packageversion[1]);
+ if ($this->_logger) {
+ $object->setLogger($this->_logger);
+ }
+ $object->setConfig($this->_config);
+ $pf = $object->parse($data, $file, $archive);
+ if (PEAR::isError($pf)) {
+ return $pf;
+ }
+ if ($this->_rawReturn) {
+ return $pf;
+ }
+ if ($pf->validate($state)) {
+ if ($this->_logger) {
+ if ($pf->getValidationWarnings(false)) {
+ foreach ($pf->getValidationWarnings() as $warning) {
+ $this->_logger->log(0, 'WARNING: ' . $warning['message']);
+ }
+ }
+ }
+ if (method_exists($pf, 'flattenFilelist')) {
+ $pf->flattenFilelist(); // for v2
+ }
+ return $pf;
+ } else {
+ if ($this->_config->get('verbose') > 0) {
+ if ($this->_logger) {
+ if ($pf->getValidationWarnings(false)) {
+ foreach ($pf->getValidationWarnings(false) as $warning) {
+ $this->_logger->log(0, 'ERROR: ' . $warning['message']);
+ }
+ }
+ }
+ }
+ $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed',
+ 2, null, null, $pf->getValidationWarnings());
+ return $a;
+ }
+ } elseif (preg_match('/]+version="([^"]+)"/', $data, $packageversion)) {
+ $a = PEAR::raiseError('package.xml file "' . $file .
+ '" has unsupported package.xml version "' . $packageversion[1] . '"');
+ return $a;
+ } else {
+ if (!class_exists('PEAR_ErrorStack')) {
+ require_once 'PEAR/ErrorStack.php';
+ }
+ PEAR_ErrorStack::staticPush('PEAR_PackageFile',
+ PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION,
+ 'warning', array('xml' => $data), 'package.xml "' . $file .
+ '" has no package.xml version');
+ $object = &$this->parserFactory('1.0');
+ $object->setConfig($this->_config);
+ $pf = $object->parse($data, $file, $archive);
+ if (PEAR::isError($pf)) {
+ return $pf;
+ }
+ if ($this->_rawReturn) {
+ return $pf;
+ }
+ if ($pf->validate($state)) {
+ if ($this->_logger) {
+ if ($pf->getValidationWarnings(false)) {
+ foreach ($pf->getValidationWarnings() as $warning) {
+ $this->_logger->log(0, 'WARNING: ' . $warning['message']);
+ }
+ }
+ }
+ if (method_exists($pf, 'flattenFilelist')) {
+ $pf->flattenFilelist(); // for v2
+ }
+ return $pf;
+ } else {
+ $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed',
+ 2, null, null, $pf->getValidationWarnings());
+ return $a;
+ }
+ }
+ }
+
+ /**
+ * Register a temporary file or directory. When the destructor is
+ * executed, all registered temporary files and directories are
+ * removed.
+ *
+ * @param string $file name of file or directory
+ * @return void
+ */
+ function addTempFile($file)
+ {
+ $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
+ }
+
+ /**
+ * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file.
+ * @access public
+ * @param string contents of package.xml file
+ * @param int package state (one of PEAR_VALIDATE_* constants)
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @using Archive_Tar to extract the files
+ * @using fromPackageFile() to load the package after the package.xml
+ * file is extracted.
+ */
+ function &fromTgzFile($file, $state)
+ {
+ if (!class_exists('Archive_Tar')) {
+ require_once 'Archive/Tar.php';
+ }
+ $tar = new Archive_Tar($file);
+ if ($this->_debug <= 1) {
+ $tar->pushErrorHandling(PEAR_ERROR_RETURN);
+ }
+ $content = $tar->listContent();
+ if ($this->_debug <= 1) {
+ $tar->popErrorHandling();
+ }
+ if (!is_array($content)) {
+ if (is_string($file) && strlen($file < 255) &&
+ (!file_exists($file) || !@is_file($file))) {
+ $ret = PEAR::raiseError("could not open file \"$file\"");
+ return $ret;
+ }
+ $file = realpath($file);
+ $ret = PEAR::raiseError("Could not get contents of package \"$file\"".
+ '. Invalid tgz file.');
+ return $ret;
+ } else {
+ if (!count($content) && !@is_file($file)) {
+ $ret = PEAR::raiseError("could not open file \"$file\"");
+ return $ret;
+ }
+ }
+ $xml = null;
+ $origfile = $file;
+ foreach ($content as $file) {
+ $name = $file['filename'];
+ if ($name == 'package2.xml') { // allow a .tgz to distribute both versions
+ $xml = $name;
+ break;
+ }
+ if ($name == 'package.xml') {
+ $xml = $name;
+ break;
+ } elseif (ereg('package.xml$', $name, $match)) {
+ $xml = $name;
+ break;
+ }
+ }
+ if ($this->_tmpdir) {
+ $tmpdir = $this->_tmpdir;
+ } else {
+ $tmpdir = System::mkTemp(array('-d', 'pear'));
+ PEAR_PackageFile::addTempFile($tmpdir);
+ }
+ $this->_extractErrors();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors'));
+ if (!$xml || !$tar->extractList(array($xml), $tmpdir)) {
+ $extra = implode("\n", $this->_extractErrors());
+ if ($extra) {
+ $extra = ' ' . $extra;
+ }
+ PEAR::staticPopErrorHandling();
+ $ret = PEAR::raiseError('could not extract the package.xml file from "' .
+ $origfile . '"' . $extra);
+ return $ret;
+ }
+ PEAR::staticPopErrorHandling();
+ $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile);
+ return $ret;
+ }
+
+ /**
+ * helper for extracting Archive_Tar errors
+ * @var array
+ * @access private
+ */
+ var $_extractErrors = array();
+
+ /**
+ * helper callback for extracting Archive_Tar errors
+ *
+ * @param PEAR_Error|null $err
+ * @return array
+ * @access private
+ */
+ function _extractErrors($err = null)
+ {
+ static $errors = array();
+ if ($err === null) {
+ $e = $errors;
+ $errors = array();
+ return $e;
+ }
+ $errors[] = $err->getMessage();
+ }
+
+ /**
+ * Create a PEAR_PackageFile_v* from a package.xml file.
+ *
+ * @access public
+ * @param string $descfile name of package xml file
+ * @param int $state package state (one of PEAR_VALIDATE_* constants)
+ * @param string|false $archive name of the archive this package.xml came
+ * from, if any
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @uses PEAR_PackageFile::fromXmlString to create the oject after the
+ * XML is loaded from the package.xml file.
+ */
+ function &fromPackageFile($descfile, $state, $archive = false)
+ {
+ if (is_string($descfile) && strlen($descfile) < 255 &&
+ (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) ||
+ (!$fp = @fopen($descfile, 'r')))) {
+ $a = PEAR::raiseError("Unable to open $descfile");
+ return $a;
+ }
+
+ // read the whole thing so we only get one cdata callback
+ // for each block of cdata
+ fclose($fp);
+ $data = file_get_contents($descfile);
+ $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive);
+ return $ret;
+ }
+
+
+ /**
+ * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file.
+ *
+ * This method is able to extract information about a package from a .tgz
+ * archive or from a XML package definition file.
+ *
+ * @access public
+ * @param string $info file name
+ * @param int $state package state (one of PEAR_VALIDATE_* constants)
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @uses fromPackageFile() if the file appears to be XML
+ * @uses fromTgzFile() to load all non-XML files
+ */
+ function &fromAnyFile($info, $state)
+ {
+ if (is_dir($info)) {
+ $dir_name = realpath($info);
+ if (file_exists($dir_name . '/package.xml')) {
+ $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package.xml', $state);
+ } elseif (file_exists($dir_name . '/package2.xml')) {
+ $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package2.xml', $state);
+ } else {
+ $info = PEAR::raiseError("No package definition found in '$info' directory");
+ }
+ return $info;
+ }
+
+ $fp = false;
+ if (is_string($info) && strlen($info) < 255 &&
+ (file_exists($info) || ($fp = @fopen($info, 'r')))) {
+ if ($fp) {
+ fclose($fp);
+ }
+ $tmp = substr($info, -4);
+ if ($tmp == '.xml') {
+ $info = &PEAR_PackageFile::fromPackageFile($info, $state);
+ } elseif ($tmp == '.tar' || $tmp == '.tgz') {
+ $info = &PEAR_PackageFile::fromTgzFile($info, $state);
+ } else {
+ $fp = fopen($info, "r");
+ $test = fread($fp, 5);
+ fclose($fp);
+ if ($test == "
diff --git a/vendor/library/Excel/phpxls/PEAR/PackageFile/Generator/v1.php b/vendor/library/Excel/phpxls/PEAR/PackageFile/Generator/v1.php
new file mode 100644
index 0000000..e6c5c94
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/PackageFile/Generator/v1.php
@@ -0,0 +1,1272 @@
+
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: v1.php,v 1.74 2008/01/03 20:26:37 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * needed for PEAR_VALIDATE_* constants
+ */
+require_once 'PEAR/Validate.php';
+require_once 'System.php';
+require_once 'PEAR/PackageFile/v2.php';
+/**
+ * This class converts a PEAR_PackageFile_v1 object into any output format.
+ *
+ * Supported output formats include array, XML string, and a PEAR_PackageFile_v2
+ * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat.
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_Generator_v1
+{
+ /**
+ * @var PEAR_PackageFile_v1
+ */
+ var $_packagefile;
+ function PEAR_PackageFile_Generator_v1(&$packagefile)
+ {
+ $this->_packagefile = &$packagefile;
+ }
+
+ function getPackagerVersion()
+ {
+ return '1.7.2';
+ }
+
+ /**
+ * @param PEAR_Packager
+ * @param bool if true, a .tgz is written, otherwise a .tar is written
+ * @param string|null directory in which to save the .tgz
+ * @return string|PEAR_Error location of package or error object
+ */
+ function toTgz(&$packager, $compress = true, $where = null)
+ {
+ require_once 'Archive/Tar.php';
+ if ($where === null) {
+ if (!($where = System::mktemp(array('-d')))) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed');
+ }
+ } elseif (!@System::mkDir(array('-p', $where))) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' .
+ ' not be created');
+ }
+ if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') &&
+ !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' .
+ ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"');
+ }
+ if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file');
+ }
+ $pkginfo = $this->_packagefile->getArray();
+ $ext = $compress ? '.tgz' : '.tar';
+ $pkgver = $pkginfo['package'] . '-' . $pkginfo['version'];
+ $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
+ if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) &&
+ !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' .
+ getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"');
+ }
+ if ($pkgfile = $this->_packagefile->getPackageFile()) {
+ $pkgdir = dirname(realpath($pkgfile));
+ $pkgfile = basename($pkgfile);
+ } else {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' .
+ 'be created from a real file');
+ }
+ // {{{ Create the package file list
+ $filelist = array();
+ $i = 0;
+
+ foreach ($this->_packagefile->getFilelist() as $fname => $atts) {
+ $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
+ if (!file_exists($file)) {
+ return PEAR::raiseError("File does not exist: $fname");
+ } else {
+ $filelist[$i++] = $file;
+ if (!isset($atts['md5sum'])) {
+ $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file));
+ }
+ $packager->log(2, "Adding file $fname");
+ }
+ }
+ // }}}
+ $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true);
+ if ($packagexml) {
+ $tar =& new Archive_Tar($dest_package, $compress);
+ $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
+ // ----- Creates with the package.xml file
+ $ok = $tar->createModify(array($packagexml), '', $where);
+ if (PEAR::isError($ok)) {
+ return $ok;
+ } elseif (!$ok) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
+ }
+ // ----- Add the content of the package
+ if (!$tar->addModify($filelist, $pkgver, $pkgdir)) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
+ }
+ return $dest_package;
+ }
+ }
+
+ /**
+ * @param string|null directory to place the package.xml in, or null for a temporary dir
+ * @param int one of the PEAR_VALIDATE_* constants
+ * @param string name of the generated file
+ * @param bool if true, then no analysis will be performed on role="php" files
+ * @return string|PEAR_Error path to the created file on success
+ */
+ function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml',
+ $nofilechecking = false)
+ {
+ if (!$this->_packagefile->validate($state, $nofilechecking)) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml',
+ null, null, null, $this->_packagefile->getValidationWarnings());
+ }
+ if ($where === null) {
+ if (!($where = System::mktemp(array('-d')))) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed');
+ }
+ } elseif (!@System::mkDir(array('-p', $where))) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' .
+ ' not be created');
+ }
+ $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
+ $np = @fopen($newpkgfile, 'wb');
+ if (!$np) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' .
+ "$name as $newpkgfile");
+ }
+ fwrite($np, $this->toXml($state, true));
+ fclose($np);
+ return $newpkgfile;
+ }
+
+ /**
+ * fix both XML encoding to be UTF8, and replace standard XML entities < > " & '
+ *
+ * @param string $string
+ * @return string
+ * @access private
+ */
+ function _fixXmlEncoding($string)
+ {
+ if (version_compare(phpversion(), '5.0.0', 'lt')) {
+ $string = utf8_encode($string);
+ }
+ return strtr($string, array(
+ '&' => '&',
+ '>' => '>',
+ '<' => '<',
+ '"' => '"',
+ '\'' => ''' ));
+ }
+
+ /**
+ * Return an XML document based on the package info (as returned
+ * by the PEAR_Common::infoFrom* methods).
+ *
+ * @return string XML data
+ */
+ function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false)
+ {
+ $this->_packagefile->setDate(date('Y-m-d'));
+ if (!$this->_packagefile->validate($state, $nofilevalidation)) {
+ return false;
+ }
+ $pkginfo = $this->_packagefile->getArray();
+ static $maint_map = array(
+ "handle" => "user",
+ "name" => "name",
+ "email" => "email",
+ "role" => "role",
+ );
+ $ret = "\n";
+ $ret .= "\n";
+ $ret .= "\n" .
+" $pkginfo[package]";
+ if (isset($pkginfo['extends'])) {
+ $ret .= "\n$pkginfo[extends]";
+ }
+ $ret .=
+ "\n ".$this->_fixXmlEncoding($pkginfo['summary'])."\n" .
+" ".trim($this->_fixXmlEncoding($pkginfo['description']))."\n \n" .
+" \n";
+ foreach ($pkginfo['maintainers'] as $maint) {
+ $ret .= " \n";
+ foreach ($maint_map as $idx => $elm) {
+ $ret .= " <$elm>";
+ $ret .= $this->_fixXmlEncoding($maint[$idx]);
+ $ret .= "$elm>\n";
+ }
+ $ret .= " \n";
+ }
+ $ret .= " \n";
+ $ret .= $this->_makeReleaseXml($pkginfo, false, $state);
+ if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) {
+ $ret .= " \n";
+ foreach ($pkginfo['changelog'] as $oldrelease) {
+ $ret .= $this->_makeReleaseXml($oldrelease, true);
+ }
+ $ret .= " \n";
+ }
+ $ret .= "\n";
+ return $ret;
+ }
+
+ // }}}
+ // {{{ _makeReleaseXml()
+
+ /**
+ * Generate part of an XML description with release information.
+ *
+ * @param array $pkginfo array with release information
+ * @param bool $changelog whether the result will be in a changelog element
+ *
+ * @return string XML data
+ *
+ * @access private
+ */
+ function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL)
+ {
+ // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!!
+ $indent = $changelog ? " " : "";
+ $ret = "$indent \n";
+ if (!empty($pkginfo['version'])) {
+ $ret .= "$indent $pkginfo[version]\n";
+ }
+ if (!empty($pkginfo['release_date'])) {
+ $ret .= "$indent $pkginfo[release_date]\n";
+ }
+ if (!empty($pkginfo['release_license'])) {
+ $ret .= "$indent $pkginfo[release_license]\n";
+ }
+ if (!empty($pkginfo['release_state'])) {
+ $ret .= "$indent $pkginfo[release_state]\n";
+ }
+ if (!empty($pkginfo['release_notes'])) {
+ $ret .= "$indent ".trim($this->_fixXmlEncoding($pkginfo['release_notes']))
+ ."\n$indent \n";
+ }
+ if (!empty($pkginfo['release_warnings'])) {
+ $ret .= "$indent ".$this->_fixXmlEncoding($pkginfo['release_warnings'])."\n";
+ }
+ if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) {
+ $ret .= "$indent \n";
+ foreach ($pkginfo['release_deps'] as $dep) {
+ $ret .= "$indent _fixXmlEncoding($c['name']) . "\"";
+ if (isset($c['default'])) {
+ $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\"";
+ }
+ $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\"";
+ $ret .= "/>\n";
+ }
+ $ret .= "$indent \n";
+ }
+ if (isset($pkginfo['provides'])) {
+ foreach ($pkginfo['provides'] as $key => $what) {
+ $ret .= "$indent recursiveXmlFilelist($pkginfo['filelist']);
+ } else {
+ foreach ($pkginfo['filelist'] as $file => $fa) {
+ if (!isset($fa['role'])) {
+ $fa['role'] = '';
+ }
+ $ret .= "$indent _fixXmlEncoding($fa['baseinstalldir']) . '"';
+ }
+ if (isset($fa['md5sum'])) {
+ $ret .= " md5sum=\"$fa[md5sum]\"";
+ }
+ if (isset($fa['platform'])) {
+ $ret .= " platform=\"$fa[platform]\"";
+ }
+ if (!empty($fa['install-as'])) {
+ $ret .= ' install-as="' .
+ $this->_fixXmlEncoding($fa['install-as']) . '"';
+ }
+ $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
+ if (empty($fa['replacements'])) {
+ $ret .= "/>\n";
+ } else {
+ $ret .= ">\n";
+ foreach ($fa['replacements'] as $r) {
+ $ret .= "$indent $v) {
+ $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
+ }
+ $ret .= "/>\n";
+ }
+ $ret .= "$indent \n";
+ }
+ }
+ }
+ $ret .= "$indent \n";
+ }
+ $ret .= "$indent \n";
+ return $ret;
+ }
+
+ /**
+ * @param array
+ * @access protected
+ */
+ function recursiveXmlFilelist($list)
+ {
+ $this->_dirs = array();
+ foreach ($list as $file => $attributes) {
+ $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes);
+ }
+ return $this->_formatDir($this->_dirs);
+ }
+
+ /**
+ * @param array
+ * @param array
+ * @param string|null
+ * @param array|null
+ * @access private
+ */
+ function _addDir(&$dirs, $dir, $file = null, $attributes = null)
+ {
+ if ($dir == array() || $dir == array('.')) {
+ $dirs['files'][basename($file)] = $attributes;
+ return;
+ }
+ $curdir = array_shift($dir);
+ if (!isset($dirs['dirs'][$curdir])) {
+ $dirs['dirs'][$curdir] = array();
+ }
+ $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes);
+ }
+
+ /**
+ * @param array
+ * @param string
+ * @param string
+ * @access private
+ */
+ function _formatDir($dirs, $indent = '', $curdir = '')
+ {
+ $ret = '';
+ if (!count($dirs)) {
+ return '';
+ }
+ if (isset($dirs['dirs'])) {
+ uksort($dirs['dirs'], 'strnatcasecmp');
+ foreach ($dirs['dirs'] as $dir => $contents) {
+ $usedir = "$curdir/$dir";
+ $ret .= "$indent \n";
+ $ret .= $this->_formatDir($contents, "$indent ", $usedir);
+ $ret .= "$indent \n";
+ }
+ }
+ if (isset($dirs['files'])) {
+ uksort($dirs['files'], 'strnatcasecmp');
+ foreach ($dirs['files'] as $file => $attribs) {
+ $ret .= $this->_formatFile($file, $attribs, $indent);
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * @param string
+ * @param array
+ * @param string
+ * @access private
+ */
+ function _formatFile($file, $attributes, $indent)
+ {
+ $ret = "$indent _fixXmlEncoding($attributes['baseinstalldir']) . '"';
+ }
+ if (isset($attributes['md5sum'])) {
+ $ret .= " md5sum=\"$attributes[md5sum]\"";
+ }
+ if (isset($attributes['platform'])) {
+ $ret .= " platform=\"$attributes[platform]\"";
+ }
+ if (!empty($attributes['install-as'])) {
+ $ret .= ' install-as="' .
+ $this->_fixXmlEncoding($attributes['install-as']) . '"';
+ }
+ $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
+ if (empty($attributes['replacements'])) {
+ $ret .= "/>\n";
+ } else {
+ $ret .= ">\n";
+ foreach ($attributes['replacements'] as $r) {
+ $ret .= "$indent $v) {
+ $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
+ }
+ $ret .= "/>\n";
+ }
+ $ret .= "$indent \n";
+ }
+ return $ret;
+ }
+
+ // {{{ _unIndent()
+
+ /**
+ * Unindent given string (?)
+ *
+ * @param string $str The string that has to be unindented.
+ * @return string
+ * @access private
+ */
+ function _unIndent($str)
+ {
+ // remove leading newlines
+ $str = preg_replace('/^[\r\n]+/', '', $str);
+ // find whitespace at the beginning of the first line
+ $indent_len = strspn($str, " \t");
+ $indent = substr($str, 0, $indent_len);
+ $data = '';
+ // remove the same amount of whitespace from following lines
+ foreach (explode("\n", $str) as $line) {
+ if (substr($line, 0, $indent_len) == $indent) {
+ $data .= substr($line, $indent_len) . "\n";
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * @return array
+ */
+ function dependenciesToV2()
+ {
+ $arr = array();
+ $this->_convertDependencies2_0($arr);
+ return $arr['dependencies'];
+ }
+
+ /**
+ * Convert a package.xml version 1.0 into version 2.0
+ *
+ * Note that this does a basic conversion, to allow more advanced
+ * features like bundles and multiple releases
+ * @param string the classname to instantiate and return. This must be
+ * PEAR_PackageFile_v2 or a descendant
+ * @param boolean if true, only valid, deterministic package.xml 1.0 as defined by the
+ * strictest parameters will be converted
+ * @return PEAR_PackageFile_v2|PEAR_Error
+ */
+ function &toV2($class = 'PEAR_PackageFile_v2', $strict = false)
+ {
+ if ($strict) {
+ if (!$this->_packagefile->validate()) {
+ $a = PEAR::raiseError('invalid package.xml version 1.0 cannot be converted' .
+ ' to version 2.0', null, null, null,
+ $this->_packagefile->getValidationWarnings(true));
+ return $a;
+ }
+ }
+ $arr = array(
+ 'attribs' => array(
+ 'version' => '2.0',
+ 'xmlns' => 'http://pear.php.net/dtd/package-2.0',
+ 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
+ 'xsi:schemaLocation' => "http://pear.php.net/dtd/tasks-1.0\n" .
+"http://pear.php.net/dtd/tasks-1.0.xsd\n" .
+"http://pear.php.net/dtd/package-2.0\n" .
+'http://pear.php.net/dtd/package-2.0.xsd',
+ ),
+ 'name' => $this->_packagefile->getPackage(),
+ 'channel' => 'pear.php.net',
+ );
+ $arr['summary'] = $this->_packagefile->getSummary();
+ $arr['description'] = $this->_packagefile->getDescription();
+ $maintainers = $this->_packagefile->getMaintainers();
+ foreach ($maintainers as $maintainer) {
+ if ($maintainer['role'] != 'lead') {
+ continue;
+ }
+ $new = array(
+ 'name' => $maintainer['name'],
+ 'user' => $maintainer['handle'],
+ 'email' => $maintainer['email'],
+ 'active' => 'yes',
+ );
+ $arr['lead'][] = $new;
+ }
+ if (!isset($arr['lead'])) { // some people... you know?
+ $arr['lead'] = array(
+ 'name' => 'unknown',
+ 'user' => 'unknown',
+ 'email' => 'noleadmaintainer@example.com',
+ 'active' => 'no',
+ );
+ }
+ if (count($arr['lead']) == 1) {
+ $arr['lead'] = $arr['lead'][0];
+ }
+ foreach ($maintainers as $maintainer) {
+ if ($maintainer['role'] == 'lead') {
+ continue;
+ }
+ $new = array(
+ 'name' => $maintainer['name'],
+ 'user' => $maintainer['handle'],
+ 'email' => $maintainer['email'],
+ 'active' => 'yes',
+ );
+ $arr[$maintainer['role']][] = $new;
+ }
+ if (isset($arr['developer']) && count($arr['developer']) == 1) {
+ $arr['developer'] = $arr['developer'][0];
+ }
+ if (isset($arr['contributor']) && count($arr['contributor']) == 1) {
+ $arr['contributor'] = $arr['contributor'][0];
+ }
+ if (isset($arr['helper']) && count($arr['helper']) == 1) {
+ $arr['helper'] = $arr['helper'][0];
+ }
+ $arr['date'] = $this->_packagefile->getDate();
+ $arr['version'] =
+ array(
+ 'release' => $this->_packagefile->getVersion(),
+ 'api' => $this->_packagefile->getVersion(),
+ );
+ $arr['stability'] =
+ array(
+ 'release' => $this->_packagefile->getState(),
+ 'api' => $this->_packagefile->getState(),
+ );
+ $licensemap =
+ array(
+ 'php' => 'http://www.php.net/license',
+ 'php license' => 'http://www.php.net/license',
+ 'lgpl' => 'http://www.gnu.org/copyleft/lesser.html',
+ 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php',
+ 'bsd style' => 'http://www.opensource.org/licenses/bsd-license.php',
+ 'bsd-style' => 'http://www.opensource.org/licenses/bsd-license.php',
+ 'mit' => 'http://www.opensource.org/licenses/mit-license.php',
+ 'gpl' => 'http://www.gnu.org/copyleft/gpl.html',
+ 'apache' => 'http://www.opensource.org/licenses/apache2.0.php'
+ );
+ if (isset($licensemap[strtolower($this->_packagefile->getLicense())])) {
+ $arr['license'] = array(
+ 'attribs' => array('uri' =>
+ $licensemap[strtolower($this->_packagefile->getLicense())]),
+ '_content' => $this->_packagefile->getLicense()
+ );
+ } else {
+ // don't use bogus uri
+ $arr['license'] = $this->_packagefile->getLicense();
+ }
+ $arr['notes'] = $this->_packagefile->getNotes();
+ $temp = array();
+ $arr['contents'] = $this->_convertFilelist2_0($temp);
+ $this->_convertDependencies2_0($arr);
+ $release = ($this->_packagefile->getConfigureOptions() || $this->_isExtension) ?
+ 'extsrcrelease' : 'phprelease';
+ if ($release == 'extsrcrelease') {
+ $arr['channel'] = 'pecl.php.net';
+ $arr['providesextension'] = $arr['name']; // assumption
+ }
+ $arr[$release] = array();
+ if ($this->_packagefile->getConfigureOptions()) {
+ $arr[$release]['configureoption'] = $this->_packagefile->getConfigureOptions();
+ foreach ($arr[$release]['configureoption'] as $i => $opt) {
+ $arr[$release]['configureoption'][$i] = array('attribs' => $opt);
+ }
+ if (count($arr[$release]['configureoption']) == 1) {
+ $arr[$release]['configureoption'] = $arr[$release]['configureoption'][0];
+ }
+ }
+ $this->_convertRelease2_0($arr[$release], $temp);
+ if ($release == 'extsrcrelease' && count($arr[$release]) > 1) {
+ // multiple extsrcrelease tags added in PEAR 1.4.1
+ $arr['dependencies']['required']['pearinstaller']['min'] = '1.4.1';
+ }
+ if ($cl = $this->_packagefile->getChangelog()) {
+ foreach ($cl as $release) {
+ $rel = array();
+ $rel['version'] =
+ array(
+ 'release' => $release['version'],
+ 'api' => $release['version'],
+ );
+ if (!isset($release['release_state'])) {
+ $release['release_state'] = 'stable';
+ }
+ $rel['stability'] =
+ array(
+ 'release' => $release['release_state'],
+ 'api' => $release['release_state'],
+ );
+ if (isset($release['release_date'])) {
+ $rel['date'] = $release['release_date'];
+ } else {
+ $rel['date'] = date('Y-m-d');
+ }
+ if (isset($release['release_license'])) {
+ if (isset($licensemap[strtolower($release['release_license'])])) {
+ $uri = $licensemap[strtolower($release['release_license'])];
+ } else {
+ $uri = 'http://www.example.com';
+ }
+ $rel['license'] = array(
+ 'attribs' => array('uri' => $uri),
+ '_content' => $release['release_license']
+ );
+ } else {
+ $rel['license'] = $arr['license'];
+ }
+ if (!isset($release['release_notes'])) {
+ $release['release_notes'] = 'no release notes';
+ }
+ $rel['notes'] = $release['release_notes'];
+ $arr['changelog']['release'][] = $rel;
+ }
+ }
+ $ret = new $class;
+ $ret->setConfig($this->_packagefile->_config);
+ if (isset($this->_packagefile->_logger) && is_object($this->_packagefile->_logger)) {
+ $ret->setLogger($this->_packagefile->_logger);
+ }
+ $ret->fromArray($arr);
+ return $ret;
+ }
+
+ /**
+ * @param array
+ * @param bool
+ * @access private
+ */
+ function _convertDependencies2_0(&$release, $internal = false)
+ {
+ $peardep = array('pearinstaller' =>
+ array('min' => '1.4.0b1')); // this is a lot safer
+ $required = $optional = array();
+ $release['dependencies'] = array('required' => array());
+ if ($this->_packagefile->hasDeps()) {
+ foreach ($this->_packagefile->getDeps() as $dep) {
+ if (!isset($dep['optional']) || $dep['optional'] == 'no') {
+ $required[] = $dep;
+ } else {
+ $optional[] = $dep;
+ }
+ }
+ foreach (array('required', 'optional') as $arr) {
+ $deps = array();
+ foreach ($$arr as $dep) {
+ // organize deps by dependency type and name
+ if (!isset($deps[$dep['type']])) {
+ $deps[$dep['type']] = array();
+ }
+ if (isset($dep['name'])) {
+ $deps[$dep['type']][$dep['name']][] = $dep;
+ } else {
+ $deps[$dep['type']][] = $dep;
+ }
+ }
+ do {
+ if (isset($deps['php'])) {
+ $php = array();
+ if (count($deps['php']) > 1) {
+ $php = $this->_processPhpDeps($deps['php']);
+ } else {
+ if (!isset($deps['php'][0])) {
+ list($key, $blah) = each ($deps['php']); // stupid buggy versions
+ $deps['php'] = array($blah[0]);
+ }
+ $php = $this->_processDep($deps['php'][0]);
+ if (!$php) {
+ break; // poor mans throw
+ }
+ }
+ $release['dependencies'][$arr]['php'] = $php;
+ }
+ } while (false);
+ do {
+ if (isset($deps['pkg'])) {
+ $pkg = array();
+ $pkg = $this->_processMultipleDepsName($deps['pkg']);
+ if (!$pkg) {
+ break; // poor mans throw
+ }
+ $release['dependencies'][$arr]['package'] = $pkg;
+ }
+ } while (false);
+ do {
+ if (isset($deps['ext'])) {
+ $pkg = array();
+ $pkg = $this->_processMultipleDepsName($deps['ext']);
+ $release['dependencies'][$arr]['extension'] = $pkg;
+ }
+ } while (false);
+ // skip sapi - it's not supported so nobody will have used it
+ // skip os - it's not supported in 1.0
+ }
+ }
+ if (isset($release['dependencies']['required'])) {
+ $release['dependencies']['required'] =
+ array_merge($peardep, $release['dependencies']['required']);
+ } else {
+ $release['dependencies']['required'] = $peardep;
+ }
+ if (!isset($release['dependencies']['required']['php'])) {
+ $release['dependencies']['required']['php'] =
+ array('min' => '4.0.0');
+ }
+ $order = array();
+ $bewm = $release['dependencies']['required'];
+ $order['php'] = $bewm['php'];
+ $order['pearinstaller'] = $bewm['pearinstaller'];
+ isset($bewm['package']) ? $order['package'] = $bewm['package'] :0;
+ isset($bewm['extension']) ? $order['extension'] = $bewm['extension'] :0;
+ $release['dependencies']['required'] = $order;
+ }
+
+ /**
+ * @param array
+ * @access private
+ */
+ function _convertFilelist2_0(&$package)
+ {
+ $ret = array('dir' =>
+ array(
+ 'attribs' => array('name' => '/'),
+ 'file' => array()
+ )
+ );
+ $package['platform'] =
+ $package['install-as'] = array();
+ $this->_isExtension = false;
+ foreach ($this->_packagefile->getFilelist() as $name => $file) {
+ $file['name'] = $name;
+ if (isset($file['role']) && $file['role'] == 'src') {
+ $this->_isExtension = true;
+ }
+ if (isset($file['replacements'])) {
+ $repl = $file['replacements'];
+ unset($file['replacements']);
+ } else {
+ unset($repl);
+ }
+ if (isset($file['install-as'])) {
+ $package['install-as'][$name] = $file['install-as'];
+ unset($file['install-as']);
+ }
+ if (isset($file['platform'])) {
+ $package['platform'][$name] = $file['platform'];
+ unset($file['platform']);
+ }
+ $file = array('attribs' => $file);
+ if (isset($repl)) {
+ foreach ($repl as $replace ) {
+ $file['tasks:replace'][] = array('attribs' => $replace);
+ }
+ if (count($repl) == 1) {
+ $file['tasks:replace'] = $file['tasks:replace'][0];
+ }
+ }
+ $ret['dir']['file'][] = $file;
+ }
+ return $ret;
+ }
+
+ /**
+ * Post-process special files with install-as/platform attributes and
+ * make the release tag.
+ *
+ * This complex method follows this work-flow to create the release tags:
+ *
+ *
+ * - if any install-as/platform exist, create a generic release and fill it with
+ * o tags for
+ * o tags for
+ * o tags for
+ * o tags for
+ * - create a release for each platform encountered and fill with
+ * o tags for
+ * o tags for
+ * o tags for
+ * o tags for
+ * o tags for
+ * o tags for
+ * o tags for
+ *
+ *
+ * It does this by accessing the $package parameter, which contains an array with
+ * indices:
+ *
+ * - platform: mapping of file => OS the file should be installed on
+ * - install-as: mapping of file => installed name
+ * - osmap: mapping of OS => list of files that should be installed
+ * on that OS
+ * - notosmap: mapping of OS => list of files that should not be
+ * installed on that OS
+ *
+ * @param array
+ * @param array
+ * @access private
+ */
+ function _convertRelease2_0(&$release, $package)
+ {
+ //- if any install-as/platform exist, create a generic release and fill it with
+ if (count($package['platform']) || count($package['install-as'])) {
+ $generic = array();
+ $genericIgnore = array();
+ foreach ($package['install-as'] as $file => $as) {
+ //o tags for
+ if (!isset($package['platform'][$file])) {
+ $generic[] = $file;
+ continue;
+ }
+ //o tags for
+ if (isset($package['platform'][$file]) &&
+ $package['platform'][$file]{0} == '!') {
+ $generic[] = $file;
+ continue;
+ }
+ //o tags for
+ if (isset($package['platform'][$file]) &&
+ $package['platform'][$file]{0} != '!') {
+ $genericIgnore[] = $file;
+ continue;
+ }
+ }
+ foreach ($package['platform'] as $file => $platform) {
+ if (isset($package['install-as'][$file])) {
+ continue;
+ }
+ if ($platform{0} != '!') {
+ //o tags for
+ $genericIgnore[] = $file;
+ }
+ }
+ if (count($package['platform'])) {
+ $oses = $notplatform = $platform = array();
+ foreach ($package['platform'] as $file => $os) {
+ // get a list of oses
+ if ($os{0} == '!') {
+ if (isset($oses[substr($os, 1)])) {
+ continue;
+ }
+ $oses[substr($os, 1)] = count($oses);
+ } else {
+ if (isset($oses[$os])) {
+ continue;
+ }
+ $oses[$os] = count($oses);
+ }
+ }
+ //- create a release for each platform encountered and fill with
+ foreach ($oses as $os => $releaseNum) {
+ $release[$releaseNum]['installconditions']['os']['name'] = $os;
+ $release[$releaseNum]['filelist'] = array('install' => array(),
+ 'ignore' => array());
+ foreach ($package['install-as'] as $file => $as) {
+ //o tags for
+ if (!isset($package['platform'][$file])) {
+ $release[$releaseNum]['filelist']['install'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ 'as' => $as,
+ ),
+ );
+ continue;
+ }
+ //o tags for
+ //
+ if (isset($package['platform'][$file]) &&
+ $package['platform'][$file] == $os) {
+ $release[$releaseNum]['filelist']['install'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ 'as' => $as,
+ ),
+ );
+ continue;
+ }
+ //o tags for
+ //
+ if (isset($package['platform'][$file]) &&
+ $package['platform'][$file] != "!$os" &&
+ $package['platform'][$file]{0} == '!') {
+ $release[$releaseNum]['filelist']['install'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ 'as' => $as,
+ ),
+ );
+ continue;
+ }
+ //o tags for
+ //
+ if (isset($package['platform'][$file]) &&
+ $package['platform'][$file] == "!$os") {
+ $release[$releaseNum]['filelist']['ignore'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ ),
+ );
+ continue;
+ }
+ //o tags for
+ //
+ if (isset($package['platform'][$file]) &&
+ $package['platform'][$file]{0} != '!' &&
+ $package['platform'][$file] != $os) {
+ $release[$releaseNum]['filelist']['ignore'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ ),
+ );
+ continue;
+ }
+ }
+ foreach ($package['platform'] as $file => $platform) {
+ if (isset($package['install-as'][$file])) {
+ continue;
+ }
+ //o tags for
+ if ($platform == "!$os") {
+ $release[$releaseNum]['filelist']['ignore'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ ),
+ );
+ continue;
+ }
+ //o tags for
+ if ($platform{0} != '!' && $platform != $os) {
+ $release[$releaseNum]['filelist']['ignore'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ ),
+ );
+ }
+ }
+ if (!count($release[$releaseNum]['filelist']['install'])) {
+ unset($release[$releaseNum]['filelist']['install']);
+ }
+ if (!count($release[$releaseNum]['filelist']['ignore'])) {
+ unset($release[$releaseNum]['filelist']['ignore']);
+ }
+ }
+ if (count($generic) || count($genericIgnore)) {
+ $release[count($oses)] = array();
+ if (count($generic)) {
+ foreach ($generic as $file) {
+ if (isset($package['install-as'][$file])) {
+ $installas = $package['install-as'][$file];
+ } else {
+ $installas = $file;
+ }
+ $release[count($oses)]['filelist']['install'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ 'as' => $installas,
+ )
+ );
+ }
+ }
+ if (count($genericIgnore)) {
+ foreach ($genericIgnore as $file) {
+ $release[count($oses)]['filelist']['ignore'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ )
+ );
+ }
+ }
+ }
+ // cleanup
+ foreach ($release as $i => $rel) {
+ if (isset($rel['filelist']['install']) &&
+ count($rel['filelist']['install']) == 1) {
+ $release[$i]['filelist']['install'] =
+ $release[$i]['filelist']['install'][0];
+ }
+ if (isset($rel['filelist']['ignore']) &&
+ count($rel['filelist']['ignore']) == 1) {
+ $release[$i]['filelist']['ignore'] =
+ $release[$i]['filelist']['ignore'][0];
+ }
+ }
+ if (count($release) == 1) {
+ $release = $release[0];
+ }
+ } else {
+ // no platform atts, but some install-as atts
+ foreach ($package['install-as'] as $file => $value) {
+ $release['filelist']['install'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ 'as' => $value
+ )
+ );
+ }
+ if (count($release['filelist']['install']) == 1) {
+ $release['filelist']['install'] = $release['filelist']['install'][0];
+ }
+ }
+ }
+ }
+
+ /**
+ * @param array
+ * @return array
+ * @access private
+ */
+ function _processDep($dep)
+ {
+ if ($dep['type'] == 'php') {
+ if ($dep['rel'] == 'has') {
+ // come on - everyone has php!
+ return false;
+ }
+ }
+ $php = array();
+ if ($dep['type'] != 'php') {
+ $php['name'] = $dep['name'];
+ if ($dep['type'] == 'pkg') {
+ $php['channel'] = 'pear.php.net';
+ }
+ }
+ switch ($dep['rel']) {
+ case 'gt' :
+ $php['min'] = $dep['version'];
+ $php['exclude'] = $dep['version'];
+ break;
+ case 'ge' :
+ if (!isset($dep['version'])) {
+ if ($dep['type'] == 'php') {
+ if (isset($dep['name'])) {
+ $dep['version'] = $dep['name'];
+ }
+ }
+ }
+ $php['min'] = $dep['version'];
+ break;
+ case 'lt' :
+ $php['max'] = $dep['version'];
+ $php['exclude'] = $dep['version'];
+ break;
+ case 'le' :
+ $php['max'] = $dep['version'];
+ break;
+ case 'eq' :
+ $php['min'] = $dep['version'];
+ $php['max'] = $dep['version'];
+ break;
+ case 'ne' :
+ $php['exclude'] = $dep['version'];
+ break;
+ case 'not' :
+ $php['conflicts'] = 'yes';
+ break;
+ }
+ return $php;
+ }
+
+ /**
+ * @param array
+ * @return array
+ */
+ function _processPhpDeps($deps)
+ {
+ $test = array();
+ foreach ($deps as $dep) {
+ $test[] = $this->_processDep($dep);
+ }
+ $min = array();
+ $max = array();
+ foreach ($test as $dep) {
+ if (!$dep) {
+ continue;
+ }
+ if (isset($dep['min'])) {
+ $min[$dep['min']] = count($min);
+ }
+ if (isset($dep['max'])) {
+ $max[$dep['max']] = count($max);
+ }
+ }
+ if (count($min) > 0) {
+ uksort($min, 'version_compare');
+ }
+ if (count($max) > 0) {
+ uksort($max, 'version_compare');
+ }
+ if (count($min)) {
+ // get the highest minimum
+ $min = array_pop($a = array_flip($min));
+ } else {
+ $min = false;
+ }
+ if (count($max)) {
+ // get the lowest maximum
+ $max = array_shift($a = array_flip($max));
+ } else {
+ $max = false;
+ }
+ if ($min) {
+ $php['min'] = $min;
+ }
+ if ($max) {
+ $php['max'] = $max;
+ }
+ $exclude = array();
+ foreach ($test as $dep) {
+ if (!isset($dep['exclude'])) {
+ continue;
+ }
+ $exclude[] = $dep['exclude'];
+ }
+ if (count($exclude)) {
+ $php['exclude'] = $exclude;
+ }
+ return $php;
+ }
+
+ /**
+ * process multiple dependencies that have a name, like package deps
+ * @param array
+ * @return array
+ * @access private
+ */
+ function _processMultipleDepsName($deps)
+ {
+ $tests = array();
+ foreach ($deps as $name => $dep) {
+ foreach ($dep as $d) {
+ $tests[$name][] = $this->_processDep($d);
+ }
+ }
+ foreach ($tests as $name => $test) {
+ $php = array();
+ $min = array();
+ $max = array();
+ $php['name'] = $name;
+ foreach ($test as $dep) {
+ if (!$dep) {
+ continue;
+ }
+ if (isset($dep['channel'])) {
+ $php['channel'] = 'pear.php.net';
+ }
+ if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') {
+ $php['conflicts'] = 'yes';
+ }
+ if (isset($dep['min'])) {
+ $min[$dep['min']] = count($min);
+ }
+ if (isset($dep['max'])) {
+ $max[$dep['max']] = count($max);
+ }
+ }
+ if (count($min) > 0) {
+ uksort($min, 'version_compare');
+ }
+ if (count($max) > 0) {
+ uksort($max, 'version_compare');
+ }
+ if (count($min)) {
+ // get the highest minimum
+ $min = array_pop($a = array_flip($min));
+ } else {
+ $min = false;
+ }
+ if (count($max)) {
+ // get the lowest maximum
+ $max = array_shift($a = array_flip($max));
+ } else {
+ $max = false;
+ }
+ if ($min) {
+ $php['min'] = $min;
+ }
+ if ($max) {
+ $php['max'] = $max;
+ }
+ $exclude = array();
+ foreach ($test as $dep) {
+ if (!isset($dep['exclude'])) {
+ continue;
+ }
+ $exclude[] = $dep['exclude'];
+ }
+ if (count($exclude)) {
+ $php['exclude'] = $exclude;
+ }
+ $ret[] = $php;
+ }
+ return $ret;
+ }
+}
+?>
\ No newline at end of file
diff --git a/vendor/library/Excel/phpxls/PEAR/PackageFile/Generator/v2.php b/vendor/library/Excel/phpxls/PEAR/PackageFile/Generator/v2.php
new file mode 100644
index 0000000..bd28c7d
--- /dev/null
+++ b/vendor/library/Excel/phpxls/PEAR/PackageFile/Generator/v2.php
@@ -0,0 +1,1531 @@
+
+ * @author Stephan Schmidt (original XML_Serializer code)
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: v2.php,v 1.39 2008/05/13 05:29:24 cellog Exp $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * file/dir manipulation routines
+ */
+require_once 'System.php';
+/**
+ * This class converts a PEAR_PackageFile_v2 object into any output format.
+ *
+ * Supported output formats include array, XML string (using S. Schmidt's
+ * XML_Serializer, slightly customized)
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @author Stephan Schmidt (original XML_Serializer code)
+ * @copyright 1997-2008 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: 1.7.2
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_Generator_v2
+{
+ /**
+ * default options for the serialization
+ * @access private
+ * @var array $_defaultOptions
+ */
+ var $_defaultOptions = array(
+ 'indent' => ' ', // string used for indentation
+ 'linebreak' => "\n", // string used for newlines
+ 'typeHints' => false, // automatically add type hin attributes
+ 'addDecl' => true, // add an XML declaration
+ 'defaultTagName' => 'XML_Serializer_Tag', // tag used for indexed arrays or invalid names
+ 'classAsTagName' => false, // use classname for objects in indexed arrays
+ 'keyAttribute' => '_originalKey', // attribute where original key is stored
+ 'typeAttribute' => '_type', // attribute for type (only if typeHints => true)
+ 'classAttribute' => '_class', // attribute for class of objects (only if typeHints => true)
+ 'scalarAsAttributes' => false, // scalar values (strings, ints,..) will be serialized as attribute
+ 'prependAttributes' => '', // prepend string for attributes
+ 'indentAttributes' => false, // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column
+ 'mode' => 'simplexml', // use 'simplexml' to use parent name as tagname if transforming an indexed array
+ 'addDoctype' => false, // add a doctype declaration
+ 'doctype' => null, // supply a string or an array with id and uri ({@see PEAR_PackageFile_Generator_v2_PEAR_PackageFile_Generator_v2_XML_Util::getDoctypeDeclaration()}
+ 'rootName' => 'package', // name of the root tag
+ 'rootAttributes' => array(
+ 'version' => '2.0',
+ 'xmlns' => 'http://pear.php.net/dtd/package-2.0',
+ 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
+ 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd',
+ ), // attributes of the root tag
+ 'attributesArray' => 'attribs', // all values in this key will be treated as attributes
+ 'contentName' => '_content', // this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray
+ 'beautifyFilelist' => false,
+ 'encoding' => 'UTF-8',
+ );
+
+ /**
+ * options for the serialization
+ * @access private
+ * @var array $options
+ */
+ var $options = array();
+
+ /**
+ * current tag depth
+ * @var integer $_tagDepth
+ */
+ var $_tagDepth = 0;
+
+ /**
+ * serilialized representation of the data
+ * @var string $_serializedData
+ */
+ var $_serializedData = null;
+ /**
+ * @var PEAR_PackageFile_v2
+ */
+ var $_packagefile;
+ /**
+ * @param PEAR_PackageFile_v2
+ */
+ function PEAR_PackageFile_Generator_v2(&$packagefile)
+ {
+ $this->_packagefile = &$packagefile;
+ }
+
+ /**
+ * @return string
+ */
+ function getPackagerVersion()
+ {
+ return '1.7.2';
+ }
+
+ /**
+ * @param PEAR_Packager
+ * @param bool generate a .tgz or a .tar
+ * @param string|null temporary directory to package in
+ */
+ function toTgz(&$packager, $compress = true, $where = null)
+ {
+ $a = null;
+ return $this->toTgz2($packager, $a, $compress, $where);
+ }
+
+ /**
+ * Package up both a package.xml and package2.xml for the same release
+ * @param PEAR_Packager
+ * @param PEAR_PackageFile_v1
+ * @param bool generate a .tgz or a .tar
+ * @param string|null temporary directory to package in
+ */
+ function toTgz2(&$packager, &$pf1, $compress = true, $where = null)
+ {
+ require_once 'Archive/Tar.php';
+ if (!$this->_packagefile->isEquivalent($pf1)) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' .
+ basename($pf1->getPackageFile()) .
+ '" is not equivalent to "' . basename($this->_packagefile->getPackageFile())
+ . '"');
+ }
+ if ($where === null) {
+ if (!($where = System::mktemp(array('-d')))) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: mktemp failed');
+ }
+ } elseif (!@System::mkDir(array('-p', $where))) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . $where . '" could' .
+ ' not be created');
+ }
+ if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') &&
+ !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' .
+ ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"');
+ }
+ if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: invalid package.xml');
+ }
+ $ext = $compress ? '.tgz' : '.tar';
+ $pkgver = $this->_packagefile->getPackage() . '-' . $this->_packagefile->getVersion();
+ $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
+ if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) &&
+ !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' .
+ getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"');
+ }
+ if ($pkgfile = $this->_packagefile->getPackageFile()) {
+ $pkgdir = dirname(realpath($pkgfile));
+ $pkgfile = basename($pkgfile);
+ } else {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' .
+ 'be created from a real file');
+ }
+ // {{{ Create the package file list
+ $filelist = array();
+ $i = 0;
+ $this->_packagefile->flattenFilelist();
+ $contents = $this->_packagefile->getContents();
+ if (isset($contents['bundledpackage'])) { // bundles of packages
+ $contents = $contents['bundledpackage'];
+ if (!isset($contents[0])) {
+ $contents = array($contents);
+ }
+ $packageDir = $where;
+ foreach ($contents as $i => $package) {
+ $fname = $package;
+ $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
+ if (!file_exists($file)) {
+ return $packager->raiseError("File does not exist: $fname");
+ }
+ $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
+ System::mkdir(array('-p', dirname($tfile)));
+ copy($file, $tfile);
+ $filelist[$i++] = $tfile;
+ $packager->log(2, "Adding package $fname");
+ }
+ } else { // normal packages
+ $contents = $contents['dir']['file'];
+ if (!isset($contents[0])) {
+ $contents = array($contents);
+ }
+
+ $packageDir = $where;
+ foreach ($contents as $i => $file) {
+ $fname = $file['attribs']['name'];
+ $atts = $file['attribs'];
+ $orig = $file;
+ $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
+ if (!file_exists($file)) {
+ return $packager->raiseError("File does not exist: $fname");
+ } else {
+ $origperms = fileperms($file);
+ $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
+ unset($orig['attribs']);
+ if (count($orig)) { // file with tasks
+ // run any package-time tasks
+ $contents = file_get_contents($file);
+ foreach ($orig as $tag => $raw) {
+ $tag = str_replace(
+ array($this->_packagefile->getTasksNs() . ':', '-'),
+ array('', '_'), $tag);
+ $task = "PEAR_Task_$tag";
+ $task = &new $task($this->_packagefile->_config,
+ $this->_packagefile->_logger,
+ PEAR_TASK_PACKAGE);
+ $task->init($raw, $atts, null);
+ $res = $task->startSession($this->_packagefile, $contents, $tfile);
+ if (!$res) {
+ continue; // skip this task
+ }
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+ $contents = $res; // save changes
+ System::mkdir(array('-p', dirname($tfile)));
+ $wp = fopen($tfile, "wb");
+ fwrite($wp, $contents);
+ fclose($wp);
+ }
+ }
+ if (!file_exists($tfile)) {
+ System::mkdir(array('-p', dirname($tfile)));
+ copy($file, $tfile);
+ }
+ chmod($tfile, $origperms);
+ $filelist[$i++] = $tfile;
+ $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($tfile), $i - 1);
+ $packager->log(2, "Adding file $fname");
+ }
+ }
+ }
+ // }}}
+ if ($pf1 !== null) {
+ $name = 'package2.xml';
+ } else {
+ $name = 'package.xml';
+ }
+ $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, $name);
+ if ($packagexml) {
+ $tar =& new Archive_Tar($dest_package, $compress);
+ $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
+ // ----- Creates with the package.xml file
+ $ok = $tar->createModify(array($packagexml), '', $where);
+ if (PEAR::isError($ok)) {
+ return $packager->raiseError($ok);
+ } elseif (!$ok) {
+ return $packager->raiseError('PEAR_Packagefile_v2::toTgz(): adding ' . $name .
+ ' failed');
+ }
+ // ----- Add the content of the package
+ if (!$tar->addModify($filelist, $pkgver, $where)) {
+ return $packager->raiseError(
+ 'PEAR_Packagefile_v2::toTgz(): tarball creation failed');
+ }
+ // add the package.xml version 1.0
+ if ($pf1 !== null) {
+ $pfgen = &$pf1->getDefaultGenerator();
+ $packagexml1 = $pfgen->toPackageFile($where, PEAR_VALIDATE_PACKAGING,
+ 'package.xml', true);
+ if (!$tar->addModify(array($packagexml1), '', $where)) {
+ return $packager->raiseError(
+ 'PEAR_Packagefile_v2::toTgz(): adding package.xml failed');
+ }
+ }
+ return $dest_package;
+ }
+ }
+
+ function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml')
+ {
+ if (!$this->_packagefile->validate($state)) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: invalid package.xml',
+ null, null, null, $this->_packagefile->getValidationWarnings());
+ }
+ if ($where === null) {
+ if (!($where = System::mktemp(array('-d')))) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: mktemp failed');
+ }
+ } elseif (!@System::mkDir(array('-p', $where))) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: "' . $where . '" could' .
+ ' not be created');
+ }
+ $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
+ $np = @fopen($newpkgfile, 'wb');
+ if (!$np) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: unable to save ' .
+ "$name as $newpkgfile");
+ }
+ fwrite($np, $this->toXml($state));
+ fclose($np);
+ return $newpkgfile;
+ }
+
+ function &toV2()
+ {
+ return $this->_packagefile;
+ }
+
+ /**
+ * Return an XML document based on the package info (as returned
+ * by the PEAR_Common::infoFrom* methods).
+ *
+ * @return string XML data
+ */
+ function toXml($state = PEAR_VALIDATE_NORMAL, $options = array())
+ {
+ $this->_packagefile->setDate(date('Y-m-d'));
+ $this->_packagefile->setTime(date('H:i:s'));
+ if (!$this->_packagefile->validate($state)) {
+ return false;
+ }
+ if (is_array($options)) {
+ $this->options = array_merge($this->_defaultOptions, $options);
+ } else {
+ $this->options = $this->_defaultOptions;
+ }
+ $arr = $this->_packagefile->getArray();
+ if (isset($arr['filelist'])) {
+ unset($arr['filelist']);
+ }
+ if (isset($arr['_lastversion'])) {
+ unset($arr['_lastversion']);
+ }
+ if ($state ^ PEAR_VALIDATE_PACKAGING && !isset($arr['bundle'])) {
+ $use = $this->_recursiveXmlFilelist($arr['contents']['dir']['file']);
+ unset($arr['contents']['dir']['file']);
+ if (isset($use['dir'])) {
+ $arr['contents']['dir']['dir'] = $use['dir'];
+ }
+ if (isset($use['file'])) {
+ $arr['contents']['dir']['file'] = $use['file'];
+ }
+ $this->options['beautifyFilelist'] = true;
+ }
+ $arr['attribs']['packagerversion'] = '1.7.2';
+ if ($this->serialize($arr, $options)) {
+ return $this->_serializedData . "\n";
+ }
+ return false;
+ }
+
+
+ function _recursiveXmlFilelist($list)
+ {
+ $dirs = array();
+ if (isset($list['attribs'])) {
+ $file = $list['attribs']['name'];
+ unset($list['attribs']['name']);
+ $attributes = $list['attribs'];
+ $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes);
+ } else {
+ foreach ($list as $a) {
+ $file = $a['attribs']['name'];
+ $attributes = $a['attribs'];
+ unset($a['attribs']);
+ $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes, $a);
+ }
+ }
+ $this->_formatDir($dirs);
+ $this->_deFormat($dirs);
+ return $dirs;
+ }
+
+ function _addDir(&$dirs, $dir, $file = null, $attributes = null, $tasks = null)
+ {
+ if (!$tasks) {
+ $tasks = array();
+ }
+ if ($dir == array() || $dir == array('.')) {
+ $dirs['file'][basename($file)] = $tasks;
+ $attributes['name'] = basename($file);
+ $dirs['file'][basename($file)]['attribs'] = $attributes;
+ return;
+ }
+ $curdir = array_shift($dir);
+ if (!isset($dirs['dir'][$curdir])) {
+ $dirs['dir'][$curdir] = array();
+ }
+ $this->_addDir($dirs['dir'][$curdir], $dir, $file, $attributes, $tasks);
+ }
+
+ function _formatDir(&$dirs)
+ {
+ if (!count($dirs)) {
+ return array();
+ }
+ $newdirs = array();
+ if (isset($dirs['dir'])) {
+ $newdirs['dir'] = $dirs['dir'];
+ }
+ if (isset($dirs['file'])) {
+ $newdirs['file'] = $dirs['file'];
+ }
+ $dirs = $newdirs;
+ if (isset($dirs['dir'])) {
+ uksort($dirs['dir'], 'strnatcasecmp');
+ foreach ($dirs['dir'] as $dir => $contents) {
+ $this->_formatDir($dirs['dir'][$dir]);
+ }
+ }
+ if (isset($dirs['file'])) {
+ uksort($dirs['file'], 'strnatcasecmp');
+ };
+ }
+
+ function _deFormat(&$dirs)
+ {
+ if (!count($dirs)) {
+ return array();
+ }
+ $newdirs = array();
+ if (isset($dirs['dir'])) {
+ foreach ($dirs['dir'] as $dir => $contents) {
+ $newdir = array();
+ $newdir['attribs']['name'] = $dir;
+ $this->_deFormat($contents);
+ foreach ($contents as $tag => $val) {
+ $newdir[$tag] = $val;
+ }
+ $newdirs['dir'][] = $newdir;
+ }
+ if (count($newdirs['dir']) == 1) {
+ $newdirs['dir'] = $newdirs['dir'][0];
+ }
+ }
+ if (isset($dirs['file'])) {
+ foreach ($dirs['file'] as $name => $file) {
+ $newdirs['file'][] = $file;
+ }
+ if (count($newdirs['file']) == 1) {
+ $newdirs['file'] = $newdirs['file'][0];
+ }
+ }
+ $dirs = $newdirs;
+ }
+
+ /**
+ * reset all options to default options
+ *
+ * @access public
+ * @see setOption(), XML_Unserializer()
+ */
+ function resetOptions()
+ {
+ $this->options = $this->_defaultOptions;
+ }
+
+ /**
+ * set an option
+ *
+ * You can use this method if you do not want to set all options in the constructor
+ *
+ * @access public
+ * @see resetOption(), XML_Serializer()
+ */
+ function setOption($name, $value)
+ {
+ $this->options[$name] = $value;
+ }
+
+ /**
+ * sets several options at once
+ *
+ * You can use this method if you do not want to set all options in the constructor
+ *
+ * @access public
+ * @see resetOption(), XML_Unserializer(), setOption()
+ */
+ function setOptions($options)
+ {
+ $this->options = array_merge($this->options, $options);
+ }
+
+ /**
+ * serialize data
+ *
+ * @access public
+ * @param mixed $data data to serialize
+ * @return boolean true on success, pear error on failure
+ */
+ function serialize($data, $options = null)
+ {
+ // if options have been specified, use them instead
+ // of the previously defined ones
+ if (is_array($options)) {
+ $optionsBak = $this->options;
+ if (isset($options['overrideOptions']) && $options['overrideOptions'] == true) {
+ $this->options = array_merge($this->_defaultOptions, $options);
+ } else {
+ $this->options = array_merge($this->options, $options);
+ }
+ }
+ else {
+ $optionsBak = null;
+ }
+
+ // start depth is zero
+ $this->_tagDepth = 0;
+
+ $this->_serializedData = '';
+ // serialize an array
+ if (is_array($data)) {
+ if (isset($this->options['rootName'])) {
+ $tagName = $this->options['rootName'];
+ } else {
+ $tagName = 'array';
+ }
+
+ $this->_serializedData .= $this->_serializeArray($data, $tagName, $this->options['rootAttributes']);
+ }
+
+ // add doctype declaration
+ if ($this->options['addDoctype'] === true) {
+ $this->_serializedData = PEAR_PackageFile_Generator_v2_XML_Util::getDoctypeDeclaration($tagName, $this->options['doctype'])
+ . $this->options['linebreak']
+ . $this->_serializedData;
+ }
+
+ // build xml declaration
+ if ($this->options['addDecl']) {
+ $atts = array();
+ if (isset($this->options['encoding']) ) {
+ $encoding = $this->options['encoding'];
+ } else {
+ $encoding = null;
+ }
+ $this->_serializedData = PEAR_PackageFile_Generator_v2_XML_Util::getXMLDeclaration('1.0', $encoding)
+ . $this->options['linebreak']
+ . $this->_serializedData;
+ }
+
+
+ if ($optionsBak !== null) {
+ $this->options = $optionsBak;
+ }
+
+ return true;
+ }
+
+ /**
+ * get the result of the serialization
+ *
+ * @access public
+ * @return string serialized XML
+ */
+ function getSerializedData()
+ {
+ if ($this->_serializedData == null ) {
+ return $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION);
+ }
+ return $this->_serializedData;
+ }
+
+ /**
+ * serialize any value
+ *
+ * This method checks for the type of the value and calls the appropriate method
+ *
+ * @access private
+ * @param mixed $value
+ * @param string $tagName
+ * @param array $attributes
+ * @return string
+ */
+ function _serializeValue($value, $tagName = null, $attributes = array())
+ {
+ if (is_array($value)) {
+ $xml = $this->_serializeArray($value, $tagName, $attributes);
+ } elseif (is_object($value)) {
+ $xml = $this->_serializeObject($value, $tagName);
+ } else {
+ $tag = array(
+ 'qname' => $tagName,
+ 'attributes' => $attributes,
+ 'content' => $value
+ );
+ $xml = $this->_createXMLTag($tag);
+ }
+ return $xml;
+ }
+
+ /**
+ * serialize an array
+ *
+ * @access private
+ * @param array $array array to serialize
+ * @param string $tagName name of the root tag
+ * @param array $attributes attributes for the root tag
+ * @return string $string serialized data
+ * @uses PEAR_PackageFile_Generator_v2_XML_Util::isValidName() to check, whether key has to be substituted
+ */
+ function _serializeArray(&$array, $tagName = null, $attributes = array())
+ {
+ $_content = null;
+
+ /**
+ * check for special attributes
+ */
+ if ($this->options['attributesArray'] !== null) {
+ if (isset($array[$this->options['attributesArray']])) {
+ $attributes = $array[$this->options['attributesArray']];
+ unset($array[$this->options['attributesArray']]);
+ }
+ /**
+ * check for special content
+ */
+ if ($this->options['contentName'] !== null) {
+ if (isset($array[$this->options['contentName']])) {
+ $_content = $array[$this->options['contentName']];
+ unset($array[$this->options['contentName']]);
+ }
+ }
+ }
+
+ /*
+ * if mode is set to simpleXML, check whether
+ * the array is associative or indexed
+ */
+ if (is_array($array) && $this->options['mode'] == 'simplexml') {
+ $indexed = true;
+ if (!count($array)) {
+ $indexed = false;
+ }
+ foreach ($array as $key => $val) {
+ if (!is_int($key)) {
+ $indexed = false;
+ break;
+ }
+ }
+
+ if ($indexed && $this->options['mode'] == 'simplexml') {
+ $string = '';
+ foreach ($array as $key => $val) {
+ if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
+ if (!isset($this->_curdir)) {
+ $this->_curdir = '';
+ }
+ $savedir = $this->_curdir;
+ if (isset($val['attribs'])) {
+ if ($val['attribs']['name'] == '/') {
+ $this->_curdir = '/';
+ } else {
+ if ($this->_curdir == '/') {
+ $this->_curdir = '';
+ }
+ $this->_curdir .= '/' . $val['attribs']['name'];
+ }
+ }
+ }
+ $string .= $this->_serializeValue( $val, $tagName, $attributes);
+ if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
+ $string .= ' ';
+ if (empty($savedir)) {
+ unset($this->_curdir);
+ } else {
+ $this->_curdir = $savedir;
+ }
+ }
+
+ $string .= $this->options['linebreak'];
+ // do indentation
+ if ($this->options['indent']!==null && $this->_tagDepth>0) {
+ $string .= str_repeat($this->options['indent'], $this->_tagDepth);
+ }
+ }
+ return rtrim($string);
+ }
+ }
+
+ if ($this->options['scalarAsAttributes'] === true) {
+ foreach ($array as $key => $value) {
+ if (is_scalar($value) && (PEAR_PackageFile_Generator_v2_XML_Util::isValidName($key) === true)) {
+ unset($array[$key]);
+ $attributes[$this->options['prependAttributes'].$key] = $value;
+ }
+ }
+ }
+
+ // check for empty array => create empty tag
+ if (empty($array)) {
+ $tag = array(
+ 'qname' => $tagName,
+ 'content' => $_content,
+ 'attributes' => $attributes
+ );
+
+ } else {
+ $this->_tagDepth++;
+ $tmp = $this->options['linebreak'];
+ foreach ($array as $key => $value) {
+ // do indentation
+ if ($this->options['indent']!==null && $this->_tagDepth>0) {
+ $tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
+ }
+
+ // copy key
+ $origKey = $key;
+ // key cannot be used as tagname => use default tag
+ $valid = PEAR_PackageFile_Generator_v2_XML_Util::isValidName($key);
+ if (PEAR::isError($valid)) {
+ if ($this->options['classAsTagName'] && is_object($value)) {
+ $key = get_class($value);
+ } else {
+ $key = $this->options['defaultTagName'];
+ }
+ }
+ $atts = array();
+ if ($this->options['typeHints'] === true) {
+ $atts[$this->options['typeAttribute']] = gettype($value);
+ if ($key !== $origKey) {
+ $atts[$this->options['keyAttribute']] = (string)$origKey;
+ }
+
+ }
+ if ($this->options['beautifyFilelist'] && $key == 'dir') {
+ if (!isset($this->_curdir)) {
+ $this->_curdir = '';
+ }
+ $savedir = $this->_curdir;
+ if (isset($value['attribs'])) {
+ if ($value['attribs']['name'] == '/') {
+ $this->_curdir = '/';
+ } else {
+ $this->_curdir .= '/' . $value['attribs']['name'];
+ }
+ }
+ }
+
+ if (is_string($value) && $value && ($value{strlen($value) - 1} == "\n")) {
+ $value .= str_repeat($this->options['indent'], $this->_tagDepth);
+ }
+ $tmp .= $this->_createXMLTag(array(
+ 'qname' => $key,
+ 'attributes' => $atts,
+ 'content' => $value )
+ );
+ if ($this->options['beautifyFilelist'] && $key == 'dir') {
+ if (isset($value['attribs'])) {
+ $tmp .= ' ';
+ if (empty($savedir)) {
+ unset($this->_curdir);
+ } else {
+ $this->_curdir = $savedir;
+ }
+ }
+ }
+ $tmp .= $this->options['linebreak'];
+ }
+
+ $this->_tagDepth--;
+ if ($this->options['indent']!==null && $this->_tagDepth>0) {
+ $tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
+ }
+
+ if (trim($tmp) === '') {
+ $tmp = null;
+ }
+
+ $tag = array(
+ 'qname' => $tagName,
+ 'content' => $tmp,
+ 'attributes' => $attributes
+ );
+ }
+ if ($this->options['typeHints'] === true) {
+ if (!isset($tag['attributes'][$this->options['typeAttribute']])) {
+ $tag['attributes'][$this->options['typeAttribute']] = 'array';
+ }
+ }
+
+ $string = $this->_createXMLTag($tag, false);
+ return $string;
+ }
+
+ /**
+ * create a tag from an array
+ * this method awaits an array in the following format
+ * array(
+ * 'qname' => $tagName,
+ * 'attributes' => array(),
+ * 'content' => $content, // optional
+ * 'namespace' => $namespace // optional
+ * 'namespaceUri' => $namespaceUri // optional
+ * )
+ *
+ * @access private
+ * @param array $tag tag definition
+ * @param boolean $replaceEntities whether to replace XML entities in content or not
+ * @return string $string XML tag
+ */
+ function _createXMLTag( $tag, $replaceEntities = true )
+ {
+ if ($this->options['indentAttributes'] !== false) {
+ $multiline = true;
+ $indent = str_repeat($this->options['indent'], $this->_tagDepth);
+
+ if ($this->options['indentAttributes'] == '_auto') {
+ $indent .= str_repeat(' ', (strlen($tag['qname'])+2));
+
+ } else {
+ $indent .= $this->options['indentAttributes'];
+ }
+ } else {
+ $multiline = false;
+ $indent = false;
+ }
+
+ if (is_array($tag['content'])) {
+ if (empty($tag['content'])) {
+ $tag['content'] = '';
+ }
+ } elseif(is_scalar($tag['content']) && (string)$tag['content'] == '') {
+ $tag['content'] = '';
+ }
+
+ if (is_scalar($tag['content']) || is_null($tag['content'])) {
+ if ($this->options['encoding'] == 'UTF-8' &&
+ version_compare(phpversion(), '5.0.0', 'lt')) {
+ $encoding = PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_UTF8_XML;
+ } else {
+ $encoding = PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML;
+ }
+ $tag = PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak'], $encoding);
+ } elseif (is_array($tag['content'])) {
+ $tag = $this->_serializeArray($tag['content'], $tag['qname'], $tag['attributes']);
+ } elseif (is_object($tag['content'])) {
+ $tag = $this->_serializeObject($tag['content'], $tag['qname'], $tag['attributes']);
+ } elseif (is_resource($tag['content'])) {
+ settype($tag['content'], 'string');
+ $tag = PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray($tag, $replaceEntities);
+ }
+ return $tag;
+ }
+}
+
+// well, it's one way to do things without extra deps ...
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.0 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available at through the world-wide-web at |
+// | http://www.php.net/license/2_02.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Authors: Stephan Schmidt |
+// +----------------------------------------------------------------------+
+//
+// $Id: v2.php,v 1.39 2008/05/13 05:29:24 cellog Exp $
+
+/**
+ * error code for invalid chars in XML name
+ */
+define("PEAR_PackageFile_Generator_v2_XML_Util_ERROR_INVALID_CHARS", 51);
+
+/**
+ * error code for invalid chars in XML name
+ */
+define("PEAR_PackageFile_Generator_v2_XML_Util_ERROR_INVALID_START", 52);
+
+/**
+ * error code for non-scalar tag content
+ */
+define("PEAR_PackageFile_Generator_v2_XML_Util_ERROR_NON_SCALAR_CONTENT", 60);
+
+/**
+ * error code for missing tag name
+ */
+define("PEAR_PackageFile_Generator_v2_XML_Util_ERROR_NO_TAG_NAME", 61);
+
+/**
+ * replace XML entities
+ */
+define("PEAR_PackageFile_Generator_v2_XML_Util_REPLACE_ENTITIES", 1);
+
+/**
+ * embedd content in a CData Section
+ */
+define("PEAR_PackageFile_Generator_v2_XML_Util_CDATA_SECTION", 2);
+
+/**
+ * do not replace entitites
+ */
+define("PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_NONE", 0);
+
+/**
+ * replace all XML entitites
+ * This setting will replace <, >, ", ' and &
+ */
+define("PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML", 1);
+
+/**
+ * replace only required XML entitites
+ * This setting will replace <, " and &
+ */
+define("PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML_REQUIRED", 2);
+
+/**
+ * replace HTML entitites
+ * @link http://www.php.net/htmlentities
+ */
+define("PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_HTML", 3);
+
+/**
+ * replace all XML entitites, and encode from ISO-8859-1 to UTF-8
+ * This setting will replace <, >, ", ' and &
+ */
+define("PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_UTF8_XML", 4);
+
+/**
+ * utility class for working with XML documents
+ *
+ * customized version of XML_Util 0.6.0
+ *
+ * @category XML
+ * @package PEAR
+ * @version 0.6.0
+ * @author Stephan Schmidt
+ * @author Gregory Beaver
+ */
+class PEAR_PackageFile_Generator_v2_XML_Util {
+
+ /**
+ * return API version
+ *
+ * @access public
+ * @static
+ * @return string $version API version
+ */
+ static function apiVersion()
+ {
+ return "0.6";
+ }
+
+ /**
+ * replace XML entities
+ *
+ * With the optional second parameter, you may select, which
+ * entities should be replaced.
+ *
+ *
+ * require_once 'XML/Util.php';
+ *
+ * // replace XML entites:
+ * $string = PEAR_PackageFile_Generator_v2_XML_Util::replaceEntities("This string contains < & >.");
+ *
+ *
+ * @access public
+ * @static
+ * @param string string where XML special chars should be replaced
+ * @param integer setting for entities in attribute values (one of PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML, PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML_REQUIRED, PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_HTML)
+ * @return string string with replaced chars
+ */
+ static function replaceEntities($string, $replaceEntities = PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML)
+ {
+ switch ($replaceEntities) {
+ case PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_UTF8_XML:
+ return strtr(utf8_encode($string),array(
+ '&' => '&',
+ '>' => '>',
+ '<' => '<',
+ '"' => '"',
+ '\'' => ''' ));
+ break;
+ case PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML:
+ return strtr($string,array(
+ '&' => '&',
+ '>' => '>',
+ '<' => '<',
+ '"' => '"',
+ '\'' => ''' ));
+ break;
+ case PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML_REQUIRED:
+ return strtr($string,array(
+ '&' => '&',
+ '<' => '<',
+ '"' => '"' ));
+ break;
+ case PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_HTML:
+ return htmlspecialchars($string);
+ break;
+ }
+ return $string;
+ }
+
+ /**
+ * build an xml declaration
+ *
+ *
+ * require_once 'XML/Util.php';
+ *
+ * // get an XML declaration:
+ * $xmlDecl = PEAR_PackageFile_Generator_v2_XML_Util::getXMLDeclaration("1.0", "UTF-8", true);
+ *
+ *
+ * @access public
+ * @static
+ * @param string $version xml version
+ * @param string $encoding character encoding
+ * @param boolean $standAlone document is standalone (or not)
+ * @return string $decl xml declaration
+ * @uses PEAR_PackageFile_Generator_v2_XML_Util::attributesToString() to serialize the attributes of the XML declaration
+ */
+ static function getXMLDeclaration($version = "1.0", $encoding = null, $standalone = null)
+ {
+ $attributes = array(
+ "version" => $version,
+ );
+ // add encoding
+ if ($encoding !== null) {
+ $attributes["encoding"] = $encoding;
+ }
+ // add standalone, if specified
+ if ($standalone !== null) {
+ $attributes["standalone"] = $standalone ? "yes" : "no";
+ }
+
+ return sprintf("", PEAR_PackageFile_Generator_v2_XML_Util::attributesToString($attributes, false));
+ }
+
+ /**
+ * build a document type declaration
+ *
+ *
+ * require_once 'XML/Util.php';
+ *
+ * // get a doctype declaration:
+ * $xmlDecl = PEAR_PackageFile_Generator_v2_XML_Util::getDocTypeDeclaration("rootTag","myDocType.dtd");
+ *
+ *
+ * @access public
+ * @static
+ * @param string $root name of the root tag
+ * @param string $uri uri of the doctype definition (or array with uri and public id)
+ * @param string $internalDtd internal dtd entries
+ * @return string $decl doctype declaration
+ * @since 0.2
+ */
+ static function getDocTypeDeclaration($root, $uri = null, $internalDtd = null)
+ {
+ if (is_array($uri)) {
+ $ref = sprintf( ' PUBLIC "%s" "%s"', $uri["id"], $uri["uri"] );
+ } elseif (!empty($uri)) {
+ $ref = sprintf( ' SYSTEM "%s"', $uri );
+ } else {
+ $ref = "";
+ }
+
+ if (empty($internalDtd)) {
+ return sprintf("", $root, $ref);
+ } else {
+ return sprintf("", $root, $ref, $internalDtd);
+ }
+ }
+
+ /**
+ * create string representation of an attribute list
+ *
+ *
+ * require_once 'XML/Util.php';
+ *
+ * // build an attribute string
+ * $att = array(
+ * "foo" => "bar",
+ * "argh" => "tomato"
+ * );
+ *
+ * $attList = PEAR_PackageFile_Generator_v2_XML_Util::attributesToString($att);
+ *
+ *
+ * @access public
+ * @static
+ * @param array $attributes attribute array
+ * @param boolean|array $sort sort attribute list alphabetically, may also be an assoc array containing the keys 'sort', 'multiline', 'indent', 'linebreak' and 'entities'
+ * @param boolean $multiline use linebreaks, if more than one attribute is given
+ * @param string $indent string used for indentation of multiline attributes
+ * @param string $linebreak string used for linebreaks of multiline attributes
+ * @param integer $entities setting for entities in attribute values (one of PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_NONE, PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML, PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML_REQUIRED, PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_HTML)
+ * @return string string representation of the attributes
+ * @uses PEAR_PackageFile_Generator_v2_XML_Util::replaceEntities() to replace XML entities in attribute values
+ * @todo allow sort also to be an options array
+ */
+ static function attributesToString($attributes, $sort = true, $multiline = false, $indent = ' ', $linebreak = "\n", $entities = PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML)
+ {
+ /**
+ * second parameter may be an array
+ */
+ if (is_array($sort)) {
+ if (isset($sort['multiline'])) {
+ $multiline = $sort['multiline'];
+ }
+ if (isset($sort['indent'])) {
+ $indent = $sort['indent'];
+ }
+ if (isset($sort['linebreak'])) {
+ $multiline = $sort['linebreak'];
+ }
+ if (isset($sort['entities'])) {
+ $entities = $sort['entities'];
+ }
+ if (isset($sort['sort'])) {
+ $sort = $sort['sort'];
+ } else {
+ $sort = true;
+ }
+ }
+ $string = '';
+ if (is_array($attributes) && !empty($attributes)) {
+ if ($sort) {
+ ksort($attributes);
+ }
+ if( !$multiline || count($attributes) == 1) {
+ foreach ($attributes as $key => $value) {
+ if ($entities != PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_NONE) {
+ $value = PEAR_PackageFile_Generator_v2_XML_Util::replaceEntities($value, $entities);
+ }
+ $string .= ' '.$key.'="'.$value.'"';
+ }
+ } else {
+ $first = true;
+ foreach ($attributes as $key => $value) {
+ if ($entities != PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_NONE) {
+ $value = PEAR_PackageFile_Generator_v2_XML_Util::replaceEntities($value, $entities);
+ }
+ if ($first) {
+ $string .= " ".$key.'="'.$value.'"';
+ $first = false;
+ } else {
+ $string .= $linebreak.$indent.$key.'="'.$value.'"';
+ }
+ }
+ }
+ }
+ return $string;
+ }
+
+ /**
+ * create a tag
+ *
+ * This method will call PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray(), which
+ * is more flexible.
+ *
+ *
+ * require_once 'XML/Util.php';
+ *
+ * // create an XML tag:
+ * $tag = PEAR_PackageFile_Generator_v2_XML_Util::createTag("myNs:myTag", array("foo" => "bar"), "This is inside the tag", "http://www.w3c.org/myNs#");
+ *
+ *
+ * @access public
+ * @static
+ * @param string $qname qualified tagname (including namespace)
+ * @param array $attributes array containg attributes
+ * @param mixed $content
+ * @param string $namespaceUri URI of the namespace
+ * @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both
+ * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line
+ * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column)
+ * @param string $linebreak string used for linebreaks
+ * @param string $encoding encoding that should be used to translate content
+ * @return string $string XML tag
+ * @see PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray()
+ * @uses PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray() to create the tag
+ */
+ static function createTag($qname, $attributes = array(), $content = null, $namespaceUri = null, $replaceEntities = PEAR_PackageFile_Generator_v2_XML_Util_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n", $encoding = PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML)
+ {
+ $tag = array(
+ "qname" => $qname,
+ "attributes" => $attributes
+ );
+
+ // add tag content
+ if ($content !== null) {
+ $tag["content"] = $content;
+ }
+
+ // add namespace Uri
+ if ($namespaceUri !== null) {
+ $tag["namespaceUri"] = $namespaceUri;
+ }
+
+ return PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $linebreak, $encoding);
+ }
+
+ /**
+ * create a tag from an array
+ * this method awaits an array in the following format
+ *
+ * array(
+ * "qname" => $qname // qualified name of the tag
+ * "namespace" => $namespace // namespace prefix (optional, if qname is specified or no namespace)
+ * "localpart" => $localpart, // local part of the tagname (optional, if qname is specified)
+ * "attributes" => array(), // array containing all attributes (optional)
+ * "content" => $content, // tag content (optional)
+ * "namespaceUri" => $namespaceUri // namespaceUri for the given namespace (optional)
+ * )
+ *
+ *
+ *
+ * require_once 'XML/Util.php';
+ *
+ * $tag = array(
+ * "qname" => "foo:bar",
+ * "namespaceUri" => "http://foo.com",
+ * "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
+ * "content" => "I'm inside the tag",
+ * );
+ * // creating a tag with qualified name and namespaceUri
+ * $string = PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray($tag);
+ *
+ *
+ * @access public
+ * @static
+ * @param array $tag tag definition
+ * @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both
+ * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line
+ * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column)
+ * @param string $linebreak string used for linebreaks
+ * @return string $string XML tag
+ * @see PEAR_PackageFile_Generator_v2_XML_Util::createTag()
+ * @uses PEAR_PackageFile_Generator_v2_XML_Util::attributesToString() to serialize the attributes of the tag
+ * @uses PEAR_PackageFile_Generator_v2_XML_Util::splitQualifiedName() to get local part and namespace of a qualified name
+ */
+ static function createTagFromArray($tag, $replaceEntities = PEAR_PackageFile_Generator_v2_XML_Util_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n", $encoding = PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML)
+ {
+ if (isset($tag["content"]) && !is_scalar($tag["content"])) {
+ return PEAR_PackageFile_Generator_v2_XML_Util::raiseError( "Supplied non-scalar value as tag content", PEAR_PackageFile_Generator_v2_XML_Util_ERROR_NON_SCALAR_CONTENT );
+ }
+
+ if (!isset($tag['qname']) && !isset($tag['localPart'])) {
+ return PEAR_PackageFile_Generator_v2_XML_Util::raiseError( 'You must either supply a qualified name (qname) or local tag name (localPart).', PEAR_PackageFile_Generator_v2_XML_Util_ERROR_NO_TAG_NAME );
+ }
+
+ // if no attributes hav been set, use empty attributes
+ if (!isset($tag["attributes"]) || !is_array($tag["attributes"])) {
+ $tag["attributes"] = array();
+ }
+
+ // qualified name is not given
+ if (!isset($tag["qname"])) {
+ // check for namespace
+ if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
+ $tag["qname"] = $tag["namespace"].":".$tag["localPart"];
+ } else {
+ $tag["qname"] = $tag["localPart"];
+ }
+ // namespace URI is set, but no namespace
+ } elseif (isset($tag["namespaceUri"]) && !isset($tag["namespace"])) {
+ $parts = PEAR_PackageFile_Generator_v2_XML_Util::splitQualifiedName($tag["qname"]);
+ $tag["localPart"] = $parts["localPart"];
+ if (isset($parts["namespace"])) {
+ $tag["namespace"] = $parts["namespace"];
+ }
+ }
+
+ if (isset($tag["namespaceUri"]) && !empty($tag["namespaceUri"])) {
+ // is a namespace given
+ if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
+ $tag["attributes"]["xmlns:".$tag["namespace"]] = $tag["namespaceUri"];
+ } else {
+ // define this Uri as the default namespace
+ $tag["attributes"]["xmlns"] = $tag["namespaceUri"];
+ }
+ }
+
+ // check for multiline attributes
+ if ($multiline === true) {
+ if ($indent === "_auto") {
+ $indent = str_repeat(" ", (strlen($tag["qname"])+2));
+ }
+ }
+
+ // create attribute list
+ $attList = PEAR_PackageFile_Generator_v2_XML_Util::attributesToString($tag["attributes"], true, $multiline, $indent, $linebreak );
+ if (!isset($tag["content"]) || (string)$tag["content"] == '') {
+ $tag = sprintf("<%s%s />", $tag["qname"], $attList);
+ } else {
+ if ($replaceEntities == PEAR_PackageFile_Generator_v2_XML_Util_REPLACE_ENTITIES) {
+ $tag["content"] = PEAR_PackageFile_Generator_v2_XML_Util::replaceEntities($tag["content"], $encoding);
+ } elseif ($replaceEntities == PEAR_PackageFile_Generator_v2_XML_Util_CDATA_SECTION) {
+ $tag["content"] = PEAR_PackageFile_Generator_v2_XML_Util::createCDataSection($tag["content"]);
+ }
+ $tag = sprintf("<%s%s>%s%s>", $tag["qname"], $attList, $tag["content"], $tag["qname"] );
+ }
+ return $tag;
+ }
+
+ /**
+ * create a start element
+ *
+ *
+ * require_once 'XML/Util.php';
+ *
+ * // create an XML start element:
+ * $tag = PEAR_PackageFile_Generator_v2_XML_Util::createStartElement("myNs:myTag", array("foo" => "bar") ,"http://www.w3c.org/myNs#");
+ *
+ *
+ * @access public
+ * @static
+ * @param string $qname qualified tagname (including namespace)
+ * @param array $attributes array containg attributes
+ * @param string $namespaceUri URI of the namespace
+ * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line
+ * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column)
+ * @param string $linebreak string used for linebreaks
+ * @return string $string XML start element
+ * @see PEAR_PackageFile_Generator_v2_XML_Util::createEndElement(), PEAR_PackageFile_Generator_v2_XML_Util::createTag()
+ */
+ static function createStartElement($qname, $attributes = array(), $namespaceUri = null, $multiline = false, $indent = '_auto', $linebreak = "\n")
+ {
+ // if no attributes hav been set, use empty attributes
+ if (!isset($attributes) || !is_array($attributes)) {
+ $attributes = array();
+ }
+
+ if ($namespaceUri != null) {
+ $parts = PEAR_PackageFile_Generator_v2_XML_Util::splitQualifiedName($qname);
+ }
+
+ // check for multiline attributes
+ if ($multiline === true) {
+ if ($indent === "_auto") {
+ $indent = str_repeat(" ", (strlen($qname)+2));
+ }
+ }
+
+ if ($namespaceUri != null) {
+ // is a namespace given
+ if (isset($parts["namespace"]) && !empty($parts["namespace"])) {
+ $attributes["xmlns:".$parts["namespace"]] = $namespaceUri;
+ } else {
+ // define this Uri as the default namespace
+ $attributes["xmlns"] = $namespaceUri;
+ }
+ }
+
+ // create attribute list
+ $attList = PEAR_PackageFile_Generator_v2_XML_Util::attributesToString($attributes, true, $multiline, $indent, $linebreak);
+ $element = sprintf("<%s%s>", $qname, $attList);
+ return $element;
+ }
+
+ /**
+ * create an end element
+ *
+ *
+ * require_once 'XML/Util.php';
+ *
+ * // create an XML start element:
+ * $tag = PEAR_PackageFile_Generator_v2_XML_Util::createEndElement("myNs:myTag");
+ *
+ *
+ * @access public
+ * @static
+ * @param string $qname qualified tagname (including namespace)
+ * @return string $string XML end element
+ * @see PEAR_PackageFile_Generator_v2_XML_Util::createStartElement(), PEAR_PackageFile_Generator_v2_XML_Util::createTag()
+ */
+ static function createEndElement($qname)
+ {
+ $element = sprintf("%s>", $qname);
+ return $element;
+ }
+
+ /**
+ * create an XML comment
+ *
+ *
+ * require_once 'XML/Util.php';
+ *
+ * // create an XML start element:
+ * $tag = PEAR_PackageFile_Generator_v2_XML_Util::createComment("I am a comment");
+ *
+ *
+ * @access public
+ * @static
+ * @param string $content content of the comment
+ * @return string $comment XML comment
+ */
+ static function createComment($content)
+ {
+ $comment = sprintf("", $content);
+ return $comment;
+ }
+
+ /**
+ * create a CData section
+ *
+ *
+ * require_once 'XML/Util.php';
+ *
+ * // create a CData section
+ * $tag = PEAR_PackageFile_Generator_v2_XML_Util::createCDataSection("I am content.");
+ *
+ *
+ * @access public
+ * @static
+ * @param string $data data of the CData section
+ * @return string $string CData section with content
+ */
+ static function createCDataSection($data)
+ {
+ return sprintf("", $data);
+ }
+
+ /**
+ * split qualified name and return namespace and local part
+ *
+ *
+ * require_once 'XML/Util.php';
+ *
+ * // split qualified tag
+ * $parts = PEAR_PackageFile_Generator_v2_XML_Util::splitQualifiedName("xslt:stylesheet");
+ *
+ * the returned array will contain two elements:
+ *