diff --git a/ajax/ajax_viewpass.php b/ajax/ajax_viewpass.php
index 1cd0f4f3..85f318a9 100644
--- a/ajax/ajax_viewpass.php
+++ b/ajax/ajax_viewpass.php
@@ -4,7 +4,7 @@
*
* @author nuxsmin
* @link http://syspass.org
- * @copyright 2012 Rubén Domínguez nuxsmin@syspass.org
+ * @copyright 2012-2014 Rubén Domínguez nuxsmin@syspass.org
*
* This file is part of sysPass.
*
@@ -22,8 +22,9 @@
* along with sysPass. If not, see .
*
*/
+
define('APP_ROOT', '..');
-include_once (APP_ROOT . "/inc/init.php");
+require_once APP_ROOT.DIRECTORY_SEPARATOR.'inc'.DIRECTORY_SEPARATOR.'init.php';
SP_Util::checkReferer('POST');
@@ -31,7 +32,7 @@ if (!SP_Init::isLoggedIn()) {
return;
}
-$accountId = SP_Common::parseParams('p', 'accountid', FALSE);
+$accountId = SP_Common::parseParams('p', 'accountid', false);
$fullTxt = SP_Common::parseParams('p', 'full', 0);
$isHistory = SP_Common::parseParams('p', 'isHistory', 0);
@@ -84,7 +85,7 @@ $message['text'][] = _('ID') . ': ' . $accountId;
$message['text'][] = _('Cuenta') . ': ' . $accountData->customer_name . " / " . $accountData->account_name;
$message['text'][] = _('IP') . ': ' . $_SERVER['REMOTE_ADDR'];
-SP_Common::wrLogInfo($message);
+SP_Log::wrLogInfo($message);
if ($fullTxt) {
?>
diff --git a/config/config.php.sample b/config/config.php.sample
new file mode 100644
index 00000000..8cb6b486
--- /dev/null
+++ b/config/config.php.sample
@@ -0,0 +1,44 @@
+ 12,
+ 'account_link' => 1,
+ 'allowed_exts' => 'BAK,CSV,DOC,DOCX,JPG,ODS,ODT,PDF,PNG,TXT,VSD,XLS,XSL',
+ 'allowed_size' => 1280,
+ 'checkupdates' => 1,
+ 'dbhost' => 'localhost',
+ 'dbname' => 'syspass',
+ 'dbpass' => 'your_secret_db_pass',
+ 'dbuser' => 'sp_admin',
+ 'debug' => 0,
+ 'demoenabled' => 0,
+ 'filesenabled' => 1,
+ 'globalsearch' => 1,
+ 'installed' => 0,
+ 'ldapbase' => 'dc=cygnux,dc=org',
+ 'ldapbindpass' => 'your_secret_ldap_pass',
+ 'ldapbinduser' => 'cn=Proxy User,ou=Users,dc=cygnux,dc=org',
+ 'ldapenabled' => 1,
+ 'ldapgroup' => 'GRP_SYSPASS',
+ 'ldapserver' => 'ldap://localhost',
+ 'ldapuserattr' => '',
+ 'logenabled' => 0,
+ 'mailenabled' => 0,
+ 'mailfrom' => 'demo@syspass.org',
+ 'mailpass' => 'your_secret_mail_pass',
+ 'mailport' => 25,
+ 'mailrequestsenabled' => 0,
+ 'mailsecurity' => 'TLS',
+ 'mailserver' => 'mail.syspass.org',
+ 'mailuser' => 'demo@syspass.org',
+ 'maintenance' => 0,
+ 'passwordsalt' => '87a77bb997f834d7859e726907233a',
+ 'session_timeout' => 600,
+ 'sitelang' => 'en_US',
+ 'version' => 1123,
+ 'wikienabled' => 0,
+ 'wikifilter' => 'vm-',
+ 'wikipageurl' => 'http://wiki.syspass.org/doku.php/demo:',
+ 'wikisearchurl' => 'http://wiki.syspass.org/wiki/doku.php/start?do=search&id=',
+);
\ No newline at end of file
diff --git a/css/styles.css b/css/styles.css
index 64b5a1e2..a4a46812 100644
--- a/css/styles.css
+++ b/css/styles.css
@@ -874,6 +874,9 @@ A:focus {text-decoration: none; color: #FF0000;}
#boxLogin #boxData input:active,
#boxLogin #boxData input:focus{border: 1px solid #5897fb;}
+#boxLogin #boxActions {float: left; width: 100%; padding: .5em; text-align: right;}
+#boxLogin #boxActions a{color: #c9c9c9;}
+
#boxLogout{
width: 250px;
margin: 0 auto;
@@ -905,15 +908,15 @@ fieldset.warning {
fieldset.warning legend { color:#b94a48 !important; }
fieldset.warning a { color:#b94a48 !important; font-weight:bold; }
-/*Install Page*/
-#install, #error{
+/*Actions and Errors Page*/
+#actions{
width: 100%;
margin: auto;
margin-bottom: 50px;
line-height: 2em;
}
-#install #logo, #error #logo{
+#actions #logo{
width: 100%;
margin-bottom: 30px;
font-size: 18px;
@@ -926,14 +929,14 @@ fieldset.warning a { color:#b94a48 !important; font-weight:bold; }
-moz-box-shadow: 0px 8px 6px -6px #a9a9a9;
}
-#install #logo #pageDesc{
+#actions #logo #pageDesc{
position: relative;
top: 30px;
left: -100px;
text-shadow: 3px 3px #fff;
}
-#install ul.errors, #error ul.errors{
+#actions ul.errors{
max-width: 40%;
margin: 0 auto;
list-style: none;
@@ -941,32 +944,32 @@ fieldset.warning a { color:#b94a48 !important; font-weight:bold; }
text-align: left;
}
-#install ul.errors>li, #error ul.errors>li{
+#actions ul.errors>li{
margin: 1.5em auto;
border-radius:5px;
padding: 0.5em;
}
-#install ul.errors>li.err_critical, #error ul.errors>li.err_critical{
+#actions ul.errors>li.err_critical{
color:#b94a48;
background:#fed7d7;
border:1px solid #f00;
}
-#install ul.errors>li.err_warning, #error ul.errors>li.err_warning{
+#actions ul.errors>li.err_warning{
color: orange;
background: #FFF2D9;
border: #ffe5b3 1px solid;
}
-#install ul.errors>li.err_ok, #error ul.errors>li.err_ok{
+#actions ul.errors>li.err_ok{
color: green;
background: #ecfde4;
border: #dbfdcb 1px solid;
font-weight: bold;
}
-#install ul.errors>li>p.hint, #error ul.errors>li>p.hint{
+#actions ul.errors>li>p.hint{
background-image:url('../imgs/info.png');
background-repeat:no-repeat;
color:#777777;
@@ -975,7 +978,7 @@ fieldset.warning a { color:#b94a48 !important; font-weight:bold; }
font-size: 12px;
}
-#install form fieldset legend{
+#actions form fieldset legend{
width:100%;
margin-top: 1em;
text-align:center;
@@ -985,9 +988,9 @@ fieldset.warning a { color:#b94a48 !important; font-weight:bold; }
font-size: 14px;
}
-#install input[type="text"],
-#install input[type="password"],
-#install input[type="email"] {
+#actions input[type="text"],
+#actions input[type="password"],
+#actions input[type="email"]{
margin-top: 0.5em;
border: 1px solid #a9a9a9;
font-size: 14px;
@@ -996,11 +999,13 @@ fieldset.warning a { color:#b94a48 !important; font-weight:bold; }
box-shadow: 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.25) inset;
}
-#install form input[type="checkbox"]+label { position:relative; margin:0; font-size:1em; text-shadow:#fff 0 1px 0; }
+#actions form input[type="checkbox"]+label { position:relative; margin:0; font-size:1em; text-shadow:#fff 0 1px 0; }
-#install .button{
+#actions .button{
+ display: inline-block;
width: 150px;
margin: 15px;
+ padding: 5px;
text-align: center;
border: 1px solid #d9d9d9;
background-color: #777;
@@ -1011,4 +1016,4 @@ fieldset.warning a { color:#b94a48 !important; font-weight:bold; }
box-shadow: 3px 3px 3px -3px #a9a9a9;
-webkit-box-shadow: 8px 8px 6px -6px #a9a9a9;
-moz-box-shadow: 8px 8px 6px -6px #a9a9a9;
-}
+}
\ No newline at end of file
diff --git a/inc/account.class.php b/inc/account.class.php
index 04694af3..eeabe1f7 100644
--- a/inc/account.class.php
+++ b/inc/account.class.php
@@ -1,40 +1,43 @@
.
-*
-*/
+/**
+ * sysPass
+ *
+ * @author nuxsmin
+ * @link http://syspass.org
+ * @copyright 2012-2014 Rubén Domínguez nuxsmin@syspass.org
+ *
+ * This file is part of sysPass.
+ *
+ * sysPass is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * sysPass 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with sysPass. If not, see .
+ *
+ */
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
/**
* Esta clase es la encargada de realizar las operaciones sobre las cuentas de sysPass.
*/
-class SP_Account {
+class SP_Account
+{
+ static $accountSearchTxt;
+ static $accountSearchCustomer;
+ static $accountSearchCategory;
+ static $accountSearchOrder;
+ static $accountSearchKey;
+
var $accountId;
- var $lastAction;
- var $lastId;
var $accountParentId;
-
- // Variables de la cuenta
var $accountUserId;
var $accountUsersId;
var $accountUserGroupId;
@@ -50,42 +53,89 @@ class SP_Account {
var $accountNotes;
var $accountOtherUserEdit;
var $accountOtherGroupEdit;
+ var $accountModHash;
- // Variable de consulta
- var $query;
+ var $lastAction;
+ var $lastId;
+ var $query; // Variable de consulta
var $queryNumRows;
- // Variable para indicar si la cuenta es desde el histórico
- var $accountIsHistory = 0;
- // Cache para grupos de usuarios de las cuentas
- var $accountCacheUserGroupsId;
- // Cache para usuarios de las cuentas
- var $accountCacheUsersId;
-
- // Variables para filtros de búsqueda
- static $accountSearchTxt;
- static $accountSearchCustomer;
- static $accountSearchCategory;
- static $accountSearchOrder;
- static $accountSearchKey;
-
+ var $accountIsHistory = 0; // Variable para indicar si la cuenta es desde el histórico
+ var $accountCacheUserGroupsId; // Cache para grupos de usuarios de las cuentas
+ var $accountCacheUsersId; // Cache para usuarios de las cuentas
+
// Variable para la caché de parámetros
var $cacheParams;
+ /**
+ * @brief Obtener los datos de usuario y modificador de una cuenta
+ * @param int $accountId con el Id de la cuenta
+ * @return object con el id de usuario y modificador.
+ */
+ public static function getAccountRequestData($accountId)
+ {
+ $query = "SELECT account_userId,"
+ . "account_userEditId,"
+ . "account_name,"
+ . "customer_name "
+ . "FROM accounts "
+ . "LEFT JOIN customers ON account_customerId = customer_id "
+ . "WHERE account_id = " . (int)$accountId . " LIMIT 1";
+ $queryRes = DB::getResults($query, __FUNCTION__);
+
+ if ($queryRes === false) {
+ return false;
+ }
+
+ return $queryRes;
+ }
+
+ /**
+ * @brief Obtiene el listado con el nombre de los usuaios de una cuenta
+ * @param int $accountId con el Id de la cuenta
+ * @return array con los nombres de los usuarios ordenados
+ */
+ public static function getAccountUsersName($accountId)
+ {
+ $query = "SELECT user_name "
+ . "FROM accUsers "
+ . "JOIN usrData ON accuser_userId = user_id "
+ . "WHERE accuser_accountId = " . (int)$accountId;
+
+ $queryRes = DB::getResults($query, __FUNCTION__);
+
+ if ($queryRes === false) {
+ return false;
+ }
+
+ if (!is_array($queryRes)) {
+ return false;
+ }
+
+ foreach ($queryRes as $users) {
+ $usersName[] = $users->user_name;
+ }
+
+ sort($usersName, SORT_STRING);
+
+ return $usersName;
+ }
+
/**
* @brief Obtener las cuentas de una búsqueda
* @param array $searchFilter filtros de búsqueda
* @return array resultado de la consulta
- */
- public function getAccounts($searchFilter){
+ */
+ public function getAccounts($searchFilter)
+ {
$isAdmin = ($_SESSION["uisadminapp"] || $_SESSION["uisadminacc"]);
- $globalSearch = (SP_Config::getValue('globalsearch',0) && $searchFilter["globalSearch"] === 1);
-
+ $globalSearch = (SP_Config::getValue('globalsearch', 0) && $searchFilter["globalSearch"] === 1);
+
$arrFilterCommon = array();
- $arrFilterSelect= array();
+ $arrFilterSelect = array();
$arrFilterUser = array();
$arrQueryWhere = array();
-
- switch ($searchFilter["keyId"]){
+
+ switch ($searchFilter["keyId"]) {
case 1:
$orderKey = "account_name";
break;
@@ -107,86 +157,86 @@ class SP_Account {
}
$querySelect = "SELECT SQL_CALC_FOUND_ROWS DISTINCT "
- . "account_id,"
- . "account_customerId,"
- . "category_name,"
- . "account_name,"
- . "account_login,"
- . "account_url,"
- . "account_notes,"
- . "account_userId,"
- . "account_userGroupId,"
- . "account_otherUserEdit,"
- . "account_otherGroupEdit,"
- . "usergroup_name,"
- . "customer_name "
- . "FROM accounts "
- . "LEFT JOIN categories ON account_categoryId = category_id "
- . "LEFT JOIN usrGroups ug ON account_userGroupId = usergroup_id "
- . "LEFT JOIN customers ON customer_id = account_customerId "
- . "LEFT JOIN accUsers ON accuser_accountId = account_id "
- . "LEFT JOIN accGroups ON accgroup_accountId = account_id";
+ . "account_id,"
+ . "account_customerId,"
+ . "category_name,"
+ . "account_name,"
+ . "account_login,"
+ . "account_url,"
+ . "account_notes,"
+ . "account_userId,"
+ . "account_userGroupId,"
+ . "account_otherUserEdit,"
+ . "account_otherGroupEdit,"
+ . "usergroup_name,"
+ . "customer_name "
+ . "FROM accounts "
+ . "LEFT JOIN categories ON account_categoryId = category_id "
+ . "LEFT JOIN usrGroups ug ON account_userGroupId = usergroup_id "
+ . "LEFT JOIN customers ON customer_id = account_customerId "
+ . "LEFT JOIN accUsers ON accuser_accountId = account_id "
+ . "LEFT JOIN accGroups ON accgroup_accountId = account_id";
- if ( $searchFilter["txtSearch"] ){
- $arrFilterCommon[] = "account_name LIKE '%".$searchFilter["txtSearch"]."%'";
- $arrFilterCommon[] = "account_login LIKE '%".$searchFilter["txtSearch"]."%'";
- $arrFilterCommon[] = "account_url LIKE '%".$searchFilter["txtSearch"]."%'";
- $arrFilterCommon[] = "account_notes LIKE '%".$searchFilter["txtSearch"]."%'";
- }
-
- if ( $searchFilter["categoryId"] != 0 ){
- $arrFilterSelect[] = "category_id = ".$searchFilter["categoryId"];
- }
- if ( $searchFilter["customerId"] != 0 ){
- $arrFilterSelect[] = "account_customerId = ".$searchFilter["customerId"];
- }
-
-
- if ( count($arrFilterCommon) > 0 ){
- $arrQueryWhere[] = "(".implode(" OR ", $arrFilterCommon).")";
- }
-
- if ( count($arrFilterSelect) > 0 ){
- $arrQueryWhere[] = "(".implode(" AND ", $arrFilterSelect).")";
- }
-
- if ( ! $isAdmin && ! $globalSearch ) {
- $arrFilterUser[] = "account_userGroupId = ".$searchFilter["groupId"];
- $arrFilterUser[] = "account_userId = ".$searchFilter["userId"];
- $arrFilterUser[] = "accgroup_groupId = ".$searchFilter["groupId"];
- $arrFilterUser[] = "accuser_userId = ".$searchFilter["userId"];
-
- $arrQueryWhere[] = "(".implode(" OR ", $arrFilterUser).")";
- }
-
- $order = ( $searchFilter["txtOrder"] == 0 ) ? 'ASC' : 'DESC';
-
- $queryOrder = " ORDER BY $orderKey ".$order;
-
- if ( $searchFilter["limitCount"] != 99 ) {
- $queryLimit = "LIMIT ".$searchFilter["limitStart"].", ".$searchFilter["limitCount"];
+ if ($searchFilter["txtSearch"]) {
+ $arrFilterCommon[] = "account_name LIKE '%" . $searchFilter["txtSearch"] . "%'";
+ $arrFilterCommon[] = "account_login LIKE '%" . $searchFilter["txtSearch"] . "%'";
+ $arrFilterCommon[] = "account_url LIKE '%" . $searchFilter["txtSearch"] . "%'";
+ $arrFilterCommon[] = "account_notes LIKE '%" . $searchFilter["txtSearch"] . "%'";
}
- if ( count($arrQueryWhere) === 1 ){
- $query = $querySelect." WHERE ".implode($arrQueryWhere)." ".$queryOrder." ".$queryLimit;
- } elseif ( count($arrQueryWhere) > 1 ){
- $query = $querySelect." WHERE ".implode(" AND ", $arrQueryWhere)." ".$queryOrder." ".$queryLimit;
- } else{
- $query = $querySelect.$queryOrder." ".$queryLimit;
+ if ($searchFilter["categoryId"] != 0) {
+ $arrFilterSelect[] = "category_id = " . $searchFilter["categoryId"];
}
-
+ if ($searchFilter["customerId"] != 0) {
+ $arrFilterSelect[] = "account_customerId = " . $searchFilter["customerId"];
+ }
+
+
+ if (count($arrFilterCommon) > 0) {
+ $arrQueryWhere[] = "(" . implode(" OR ", $arrFilterCommon) . ")";
+ }
+
+ if (count($arrFilterSelect) > 0) {
+ $arrQueryWhere[] = "(" . implode(" AND ", $arrFilterSelect) . ")";
+ }
+
+ if (!$isAdmin && !$globalSearch) {
+ $arrFilterUser[] = "account_userGroupId = " . $searchFilter["groupId"];
+ $arrFilterUser[] = "account_userId = " . $searchFilter["userId"];
+ $arrFilterUser[] = "accgroup_groupId = " . $searchFilter["groupId"];
+ $arrFilterUser[] = "accuser_userId = " . $searchFilter["userId"];
+
+ $arrQueryWhere[] = "(" . implode(" OR ", $arrFilterUser) . ")";
+ }
+
+ $order = ($searchFilter["txtOrder"] == 0) ? 'ASC' : 'DESC';
+
+ $queryOrder = " ORDER BY $orderKey " . $order;
+
+ if ($searchFilter["limitCount"] != 99) {
+ $queryLimit = "LIMIT " . $searchFilter["limitStart"] . ", " . $searchFilter["limitCount"];
+ }
+
+ if (count($arrQueryWhere) === 1) {
+ $query = $querySelect . " WHERE " . implode($arrQueryWhere) . " " . $queryOrder . " " . $queryLimit;
+ } elseif (count($arrQueryWhere) > 1) {
+ $query = $querySelect . " WHERE " . implode(" AND ", $arrQueryWhere) . " " . $queryOrder . " " . $queryLimit;
+ } else {
+ $query = $querySelect . $queryOrder . " " . $queryLimit;
+ }
+
$this->query = $query;
-
- // Consulta de la búsqueda de cuentas
- $queryRes = DB::getResults($query, __FUNCTION__, TRUE);
- if ( $queryRes === FALSE ){
- return FALSE;
+ // Consulta de la búsqueda de cuentas
+ $queryRes = DB::getResults($query, __FUNCTION__, true);
+
+ if ($queryRes === false) {
+ return false;
}
-
+
// Obtenemos el número de registros totales de la consulta sin contar el LIMIT
$resQueryNumRows = DB::getResults("SELECT FOUND_ROWS() as numRows", __FUNCTION__);
- $this->queryNumRows = $resQueryNumRows->numRows;
+ $this->queryNumRows = $resQueryNumRows->numRows;
$_SESSION["accountSearchTxt"] = $searchFilter["txtSearch"];
$_SESSION["accountSearchCustomer"] = $searchFilter["customerId"];
@@ -196,133 +246,60 @@ class SP_Account {
$_SESSION["accountSearchStart"] = $searchFilter["limitStart"];
$_SESSION["accountSearchLimit"] = $searchFilter["limitCount"];
$_SESSION["accountGlobalSearch"] = $searchFilter["globalSearch"];
-
- return $queryRes;
- }
- /**
- * @brief Obtener los datos de una cuenta
- * @return none
- *
- * Esta funcion realiza la consulta a la BBDD y guarda los datos en las variables de la clase.
- */
- public function getAccount(){
- $query = "SELECT account_id,"
- . "account_name,"
- . "account_categoryId,"
- . "account_userId,"
- . "account_customerId,"
- . "account_userGroupId,"
- . "account_userEditId,"
- . "category_name,"
- . "account_login,"
- . "account_url,"
- . "account_pass,"
- . "account_IV,"
- . "account_notes,"
- . "account_countView,"
- . "account_countDecrypt,"
- . "account_dateAdd,"
- . "account_dateEdit,"
- . "account_otherUserEdit,"
- . "account_otherGroupEdit,"
- . "u1.user_name as user_name,"
- . "u2.user_name as user_editName,"
- . "usergroup_name,"
- . "customer_name "
- . "FROM accounts "
- . "LEFT JOIN categories ON account_categoryId = category_id "
- . "LEFT JOIN usrGroups ug ON account_userGroupId = usergroup_id "
- . "LEFT JOIN usrData u1 ON account_userId = u1.user_id "
- . "LEFT JOIN usrData u2 ON account_userEditId = u2.user_id "
- . "LEFT JOIN customers ON account_customerId = customer_id "
- . "WHERE account_id = ".(int)$this->accountId." LIMIT 1";
-
- $queryRes = DB::getResults($query, __FUNCTION__);
-
- if ( $queryRes === FALSE ){
- return FALSE;
- }
-
- $this->accountUserId = $queryRes->account_userId;
- $this->accountUserGroupId = $queryRes->account_userGroupId;
- $this->accountOtherUserEdit = $queryRes->account_otherUserEdit;
- $this->accountOtherGroupEdit = $queryRes->account_otherGroupEdit;
-
return $queryRes;
}
/**
* @brief Obtener los datos del histórico de una cuenta
* @return none
- *
+ *
* Esta funcion realiza la consulta a la BBDD y guarda los datos del histórico en las variables de la clase.
- */
- public function getAccountHistory(){
+ */
+ public function getAccountHistory()
+ {
$query = "SELECT acchistory_accountId as account_id,"
- . "acchistory_customerId as account_customerId,"
- . "acchistory_categoryId as account_categoryId,"
- . "acchistory_name as account_name,"
- . "acchistory_login as account_login,"
- . "acchistory_url as account_url,"
- . "acchistory_pass as account_pass,"
- . "acchistory_IV as account_IV,"
- . "acchistory_notes as account_notes,"
- . "acchistory_countView as account_countView,"
- . "acchistory_countDecrypt as account_countDecrypt,"
- . "acchistory_dateAdd as account_dateAdd,"
- . "acchistory_dateEdit as account_dateEdit,"
- . "acchistory_userId as account_userId,"
- . "acchistory_userGroupId as account_useGroupId,"
- . "acchistory_userEditId as account_userEditId,"
- . "acchistory_isModify,"
- . "acchistory_isDeleted,"
- . "acchistory_otherUserEdit as account_otherUserEdit,"
- . "acchistory_otherGroupEdit as account_otherGroupEdit,"
- . "u1.user_name,"
- . "usergroup_name,"
- . "u2.user_name as user_editName,"
- . "category_name, customer_name "
- . "FROM accHistory "
- . "LEFT JOIN categories ON acchistory_categoryId = category_id "
- . "LEFT JOIN usrGroups ON acchistory_userGroupId = usergroup_id "
- . "LEFT JOIN usrData u1 ON acchistory_userId = u1.user_id "
- . "LEFT JOIN usrData u2 ON acchistory_userEditId = u2.user_id "
- . "LEFT JOIN customers ON acchistory_customerId = customer_id "
- . "WHERE acchistory_id = ".(int)$this->accountId." LIMIT 1";
+ . "acchistory_customerId as account_customerId,"
+ . "acchistory_categoryId as account_categoryId,"
+ . "acchistory_name as account_name,"
+ . "acchistory_login as account_login,"
+ . "acchistory_url as account_url,"
+ . "acchistory_pass as account_pass,"
+ . "acchistory_IV as account_IV,"
+ . "acchistory_notes as account_notes,"
+ . "acchistory_countView as account_countView,"
+ . "acchistory_countDecrypt as account_countDecrypt,"
+ . "acchistory_dateAdd as account_dateAdd,"
+ . "acchistory_dateEdit as account_dateEdit,"
+ . "acchistory_userId as account_userId,"
+ . "acchistory_userGroupId as account_useGroupId,"
+ . "acchistory_userEditId as account_userEditId,"
+ . "acchistory_isModify,"
+ . "acchistory_isDeleted,"
+ . "acchistory_otherUserEdit as account_otherUserEdit,"
+ . "acchistory_otherGroupEdit as account_otherGroupEdit,"
+ . "u1.user_name,"
+ . "usergroup_name,"
+ . "u2.user_name as user_editName,"
+ . "category_name, customer_name "
+ . "FROM accHistory "
+ . "LEFT JOIN categories ON acchistory_categoryId = category_id "
+ . "LEFT JOIN usrGroups ON acchistory_userGroupId = usergroup_id "
+ . "LEFT JOIN usrData u1 ON acchistory_userId = u1.user_id "
+ . "LEFT JOIN usrData u2 ON acchistory_userEditId = u2.user_id "
+ . "LEFT JOIN customers ON acchistory_customerId = customer_id "
+ . "WHERE acchistory_id = " . (int)$this->accountId . " LIMIT 1";
$queryRes = DB::getResults($query, __FUNCTION__);
- if ( $queryRes === FALSE ){
- return FALSE;
+ if ($queryRes === false) {
+ return false;
}
$this->accountUserId = $queryRes->acchistory_userId;
$this->accountUserGroupId = $queryRes->acchistory_userGroupId;
$this->accountOtherUserEdit = $queryRes->acchistory_otherUserEdit;
$this->accountOtherGroupEdit = $queryRes->acchistory_otherGroupEdit;
-
- return $queryRes;
- }
-
- /**
- * @brief Obtener los datos de usuario y modificador de una cuenta
- * @param int $accountId con el Id de la cuenta
- * @return object con el id de usuario y modificador.
- */
- public static function getAccountRequestData($accountId){
- $query = "SELECT account_userId,"
- . "account_userEditId,"
- . "account_name,"
- . "customer_name "
- . "FROM accounts "
- . "LEFT JOIN customers ON account_customerId = customer_id "
- . "WHERE account_id = ".(int)$accountId." LIMIT 1";
- $queryRes = DB::getResults($query, __FUNCTION__);
-
- if ( $queryRes === FALSE ){
- return FALSE;
- }
return $queryRes;
}
@@ -330,784 +307,772 @@ class SP_Account {
/**
* @brief Actualiza los datos de una cuenta en la BBDD
* @return bool
- */
- public function updateAccount(){
+ */
+ public function updateAccount()
+ {
$message['action'][] = __FUNCTION__;
-
+
// Guardamos una copia de la cuenta en el histórico
- if ( ! $this->addHistory($this->accountId, $this->accountUserEditId, FALSE) ){
+ if (!$this->addHistory($this->accountId, $this->accountUserEditId, false)) {
$message['text'][] = _('Error al actualizar el historial');
- SP_Common::wrLogInfo($message);
- return FALSE;
+ SP_Log::wrLogInfo($message);
+ return false;
}
- if ( ! SP_Groups::updateGroupsForAccount($this->accountId, $this->accountUserGroupsId) ){
+ if (!SP_Groups::updateGroupsForAccount($this->accountId, $this->accountUserGroupsId)) {
$message['text'][] = _('Error al actualizar los grupos secundarios');
- SP_Common::wrLogInfo($message);
+ SP_Log::wrLogInfo($message);
$message['text'] = array();
}
-
- if ( ! SP_Users::updateUsersForAccount($this->accountId, $this->accountUsersId) ){
+
+ if (!SP_Users::updateUsersForAccount($this->accountId, $this->accountUsersId)) {
$message['text'][] = _('Error al actualizar los usuarios de la cuenta');
- SP_Common::wrLogInfo($message);
+ SP_Log::wrLogInfo($message);
$message['text'] = array();
}
$query = "UPDATE accounts SET "
- . "account_customerId = '".DB::escape($this->accountCustomerId)."',"
- . "account_categoryId = ".(int)$this->accountCategoryId.","
- . "account_name = '".DB::escape($this->accountName)."',"
- . "account_login = '".DB::escape($this->accountLogin)."',"
- . "account_url = '".DB::escape($this->accountUrl)."',"
- . "account_notes = '".DB::escape($this->accountNotes)."',"
- . "account_userEditId = ".(int)$this->accountUserEditId.","
- . "account_dateEdit = NOW(), "
- . "account_otherUserEdit = ".(int)$this->accountOtherUserEdit.","
- . "account_otherGroupEdit = ".(int)$this->accountOtherGroupEdit." "
- . "WHERE account_id = ".(int)$this->accountId;
+ . "account_customerId = '" . DB::escape($this->accountCustomerId) . "',"
+ . "account_categoryId = " . (int)$this->accountCategoryId . ","
+ . "account_name = '" . DB::escape($this->accountName) . "',"
+ . "account_login = '" . DB::escape($this->accountLogin) . "',"
+ . "account_url = '" . DB::escape($this->accountUrl) . "',"
+ . "account_notes = '" . DB::escape($this->accountNotes) . "',"
+ . "account_userEditId = " . (int)$this->accountUserEditId . ","
+ . "account_dateEdit = NOW(), "
+ . "account_otherUserEdit = " . (int)$this->accountOtherUserEdit . ","
+ . "account_otherGroupEdit = " . (int)$this->accountOtherGroupEdit . " "
+ . "WHERE account_id = " . (int)$this->accountId;
- if ( DB::doQuery($query, __FUNCTION__) === FALSE ){
- return FALSE;
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
$accountInfo = array('customer_name');
$this->getAccountInfoById($accountInfo);
-
+
$message['action'] = _('Cuenta actualizada');
- $message['text'][] = _('Cliente').": ".$this->cacheParams['customer_name'];
- $message['text'][] = _('Cuenta').": $this->accountName ($this->accountId)";
-
- SP_Common::wrLogInfo($message);
+ $message['text'][] = SP_Html::strongText(_('Cliente') . ": ") . $this->cacheParams['customer_name'];
+ $message['text'][] = SP_Html::strongText(_('Cuenta') . ": ") . "$this->accountName ($this->accountId)";
+
+ SP_Log::wrLogInfo($message);
SP_Common::sendEmail($message);
-
- return TRUE;
+
+ return true;
}
- /**
- * @brief Actualiza la clave de una cuenta en la BBDD
- * @param bool $isMasive para no actualizar el histórico ni enviar mensajes
- * @return bool
- */
- public function updateAccountPass($isMassive = FALSE){
- $message['action'] = __FUNCTION__;
-
- // No actualizar el histórico si es por cambio de clave maestra
- if ( ! $isMassive ){
- // Guardamos una copia de la cuenta en el histórico
- if ( ! $this->addHistory($this->accountId, $this->accountUserEditId, FALSE) ){
- $message['text'][] = _('Error al actualizar el historial');
- SP_Common::wrLogInfo($message);
- return FALSE;
- }
- }
-
- $query = "UPDATE accounts SET "
- . "account_pass = '".DB::escape($this->accountPass)."',"
- . "account_IV = '".DB::escape($this->accountIV)."',"
- . "account_userEditId = ".(int)$this->accountUserEditId.","
- . "account_dateEdit = NOW() "
- . "WHERE account_id = ".(int)$this->accountId;
-
- if ( DB::doQuery($query, __FUNCTION__) === FALSE ){
- return FALSE;
- }
-
- // No escribir en el log ni enviar correos si la actualización es
- // por cambio de clave maestra...
- if ( ! $isMassive ){
- $accountInfo = array('customer_name','account_name');
- $this->getAccountInfoById($accountInfo);
-
- $message['action'] = _('Modificar Clave');
- $message['text'][] = _('Cliente').": ".$this->cacheParams['customer_name'];
- $message['text'][] = _('Cuenta').": ".$this->cacheParams['account_name']." ($this->accountId)";
-
- SP_Common::wrLogInfo($message);
- SP_Common::sendEmail($message);
- }
-
- return TRUE;
- }
-
- /**
- * @brief Actualiza la clave del histórico de una cuenta en la BBDD
- * @param int $id con el id del registro a actualizar
- * @param string $newHash con el hash de la clave maestra
- * @return bool
- */
- public function updateAccountHistoryPass($id, $newHash){
- $query = "UPDATE accHistory SET "
- . "acchistory_pass = '".DB::escape($this->accountPass)."',"
- . "acchistory_IV = '".DB::escape($this->accountIV)."',"
- . "acchistory_mPassHash = '" . DB::escape($newHash)."' "
- . "WHERE acchistory_id = ".(int)$id;
-
- if ( DB::doQuery($query, __FUNCTION__) === FALSE ){
- return FALSE;
- }
-
- return TRUE;
- }
-
- /**
- * @brief Crea una nueva cuenta en la BBDD
- * @return bool
- */
- public function createAccount(){
- $query = "INSERT INTO accounts SET "
- . "account_customerId = ".(int)$this->accountCustomerId.","
- . "account_categoryId = ".(int)$this->accountCategoryId.","
- . "account_name = '".DB::escape($this->accountName)."',"
- . "account_login = '".DB::escape($this->accountLogin)."',"
- . "account_url = '".DB::escape($this->accountUrl)."',"
- . "account_pass = '$this->accountPass',"
- . "account_IV = '".DB::escape($this->accountIV)."',"
- . "account_notes = '".DB::escape($this->accountNotes)."',"
- . "account_dateAdd = NOW(),"
- . "account_userId = ".(int)$this->accountUserId.","
- . "account_userGroupId = ".(int)$this->accountUserGroupId.","
- . "account_otherUserEdit = ".(int)$this->accountOtherUserEdit.","
- . "account_otherGroupEdit = ".(int)$this->accountOtherGroupEdit;
-
- if ( DB::doQuery($query, __FUNCTION__) === FALSE ){
- return FALSE;
- }
-
- $this->accountId = DB::$lastId;
-
- $message['action'] = __FUNCTION__;
-
- if ( ! SP_Groups::addGroupsForAccount($this->accountId, $this->accountUserGroupsId) ){
- $message['text'][] = _('Error al actualizar los grupos secundarios');
- SP_Common::wrLogInfo($message);
- $message['text'] = array();
- }
-
- if ( ! SP_Users::addUsersForAccount($this->accountId, $this->accountUsersId) ){
- $message['text'][] = _('Error al actualizar los usuarios de la cuenta');
- SP_Common::wrLogInfo($message);
- $message['text'] = array();
- }
-
- $accountInfo = array('customer_name');
- $this->getAccountInfoById($accountInfo);
-
- $message['action'] = _('Nueva Cuenta');
- $message['text'][] = _('Cliente').": ".$this->cacheParams['customer_name'];
- $message['text'][] = _('Cuenta').": $this->accountName ($this->accountId)";
-
- SP_Common::wrLogInfo($message);
- SP_Common::sendEmail($message);
-
- return TRUE;
- }
-
- /**
- * @brief Elimina los datos de una cuenta en la BBDD
- * @return bool
- */
- public function deleteAccount(){
- // Guardamos una copia de la cuenta en el histórico
- $this->addHistory(TRUE) || die (_('ERROR: Error en la operación.'));
-
- $accountInfo = array('account_name,customer_name');
- $this->getAccountInfoById($accountInfo);
-
- $message['action'] = _('Eliminar Cuenta');
- $message['text'][] = _('Cliente').": ".$this->cacheParams['customer_name'];
- $message['text'][] = _('Cuenta').": ".$this->cacheParams['account_name']." ($this->accountId)";
-
- $query = "DELETE FROM accounts "
- . "WHERE account_id = ".(int)$this->accountId." LIMIT 1";
-
- if ( DB::doQuery($query, __FUNCTION__) === FALSE ){
- return FALSE;
- }
-
- if ( ! SP_Groups::deleteGroupsForAccount($this->accountId) ){
- $message['text'][] = _('Error al eliminar grupos asociados a la cuenta');
- }
-
- if ( ! SP_Users::deleteUsersForAccount($this->accountId) ){
- $message['text'][] = _('Error al eliminar usuarios asociados a la cuenta');
- }
-
- if ( ! SP_Files::deleteAccountFiles($this->accountId) ){
- $message['text'][] = _('Error al eliminar archivos asociados a la cuenta');
- }
-
- SP_Common::wrLogInfo($message);
- SP_Common::sendEmail($message);
-
- return TRUE;
- }
-
/**
* @brief Crear un nuevo registro de histório de cuenta en la BBDD
+ * @param bool $isDelete indica que la cuenta es eliminada
* @return bool
- */
- private function addHistory ($isDelete){
+ */
+ private function addHistory($isDelete = false)
+ {
$objAccountHist = new SP_Account;
$objAccountHist->accountId = $this->accountId;
$accountData = $objAccountHist->getAccount();
- $isModify = ($isDelete === FALSE ) ? 1 : 0;
- $isDelete = ($isDelete === FALSE ) ? 0 : 1;
+ $isModify = ($isDelete === false) ? 1 : 0;
+ $isDelete = ($isDelete === false) ? 0 : 1;
$query = "INSERT INTO accHistory SET "
- . "acchistory_accountId = " . $objAccountHist->accountId . ","
- . "acchistory_customerId = " . $accountData->account_customerId . ","
- . "acchistory_name = '" . DB::escape($accountData->account_name) . "',"
- . "acchistory_login = '" . DB::escape($accountData->account_login) . "',"
- . "acchistory_url = '" . DB::escape($accountData->account_url) . "',"
- . "acchistory_pass = '" . DB::escape($accountData->account_pass) . "',"
- . "acchistory_IV = '" . DB::escape($accountData->account_IV) . "',"
- . "acchistory_notes = '" . DB::escape($accountData->account_notes) . "',"
- . "acchistory_countView = " . $accountData->account_countView . ","
- . "acchistory_countDecrypt = " . $accountData->account_countDecrypt . ","
- . "acchistory_dateAdd = '" . $accountData->account_dateAdd . "',"
- . "acchistory_dateEdit = '" . $accountData->account_dateEdit . "',"
- . "acchistory_userId = " . $accountData->account_userId . ","
- . "acchistory_userGroupId = " . $accountData->account_userGroupId . ","
- . "acchistory_userEditId = " . $accountData->account_userEditId . ","
- . "acchistory_isModify = " . $isModify . ","
- . "acchistory_isDeleted = " . $isDelete . ","
- . "acchistory_otherUserEdit = " . $accountData->account_otherUserEdit . ","
- . "acchistory_otherGroupEdit = " . $accountData->account_otherGroupEdit . ","
- . "acchistory_mPassHash = '" . DB::escape(SP_Config::getConfigValue('masterPwd'))."'";
+ . "acchistory_accountId = " . $objAccountHist->accountId . ","
+ . "acchistory_customerId = " . $accountData->account_customerId . ","
+ . "acchistory_name = '" . DB::escape($accountData->account_name) . "',"
+ . "acchistory_login = '" . DB::escape($accountData->account_login) . "',"
+ . "acchistory_url = '" . DB::escape($accountData->account_url) . "',"
+ . "acchistory_pass = '" . DB::escape($accountData->account_pass) . "',"
+ . "acchistory_IV = '" . DB::escape($accountData->account_IV) . "',"
+ . "acchistory_notes = '" . DB::escape($accountData->account_notes) . "',"
+ . "acchistory_countView = " . $accountData->account_countView . ","
+ . "acchistory_countDecrypt = " . $accountData->account_countDecrypt . ","
+ . "acchistory_dateAdd = '" . $accountData->account_dateAdd . "',"
+ . "acchistory_dateEdit = '" . $accountData->account_dateEdit . "',"
+ . "acchistory_userId = " . $accountData->account_userId . ","
+ . "acchistory_userGroupId = " . $accountData->account_userGroupId . ","
+ . "acchistory_userEditId = " . $accountData->account_userEditId . ","
+ . "acchistory_isModify = " . $isModify . ","
+ . "acchistory_isDeleted = " . $isDelete . ","
+ . "acchistory_otherUserEdit = " . $accountData->account_otherUserEdit . ","
+ . "acchistory_otherGroupEdit = " . $accountData->account_otherGroupEdit . ","
+ . "acchistory_mPassHash = '" . DB::escape(SP_Config::getConfigValue('masterPwd')) . "'";
- if ( DB::doQuery($query, __FUNCTION__) === FALSE ){
- return FALSE;
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
- return TRUE;
+ return true;
+ }
+
+ /**
+ * @brief Obtener los datos de una cuenta
+ * @return none
+ *
+ * Esta funcion realiza la consulta a la BBDD y guarda los datos en las variables de la clase.
+ */
+ public function getAccount()
+ {
+ $query = "SELECT account_id,"
+ . "account_name,"
+ . "account_categoryId,"
+ . "account_userId,"
+ . "account_customerId,"
+ . "account_userGroupId,"
+ . "account_userEditId,"
+ . "category_name,"
+ . "account_login,"
+ . "account_url,"
+ . "account_pass,"
+ . "account_IV,"
+ . "account_notes,"
+ . "account_countView,"
+ . "account_countDecrypt,"
+ . "account_dateAdd,"
+ . "account_dateEdit,"
+ . "account_otherUserEdit,"
+ . "account_otherGroupEdit,"
+ . "u1.user_name as user_name,"
+ . "u2.user_name as user_editName,"
+ . "usergroup_name,"
+ . "customer_name, "
+ . "CONCAT(account_name,account_categoryId,account_customerId,account_login,account_url,account_notes) as modHash "
+ . "FROM accounts "
+ . "LEFT JOIN categories ON account_categoryId = category_id "
+ . "LEFT JOIN usrGroups ug ON account_userGroupId = usergroup_id "
+ . "LEFT JOIN usrData u1 ON account_userId = u1.user_id "
+ . "LEFT JOIN usrData u2 ON account_userEditId = u2.user_id "
+ . "LEFT JOIN customers ON account_customerId = customer_id "
+ . "WHERE account_id = " . (int)$this->accountId . " LIMIT 1";
+
+ $queryRes = DB::getResults($query, __FUNCTION__);
+
+ if ($queryRes === false) {
+ return false;
+ }
+
+ $this->accountUserId = $queryRes->account_userId;
+ $this->accountUserGroupId = $queryRes->account_userGroupId;
+ $this->accountOtherUserEdit = $queryRes->account_otherUserEdit;
+ $this->accountOtherGroupEdit = $queryRes->account_otherGroupEdit;
+ $this->accountModHash = $queryRes->modHash;
+
+ return $queryRes;
+ }
+
+ /**
+ * @brief Obtener los datos de una cuenta con el id
+ * @param array $params con los campos de la BBDD a obtener
+ * @return bool
+ *
+ * Se guardan los datos en la variable $cacheParams de la clase para consultarlos
+ * posteriormente.
+ */
+ private function getAccountInfoById($params)
+ {
+ if (!is_array($params)) {
+ return false;
+ }
+
+ if (is_array($this->cacheParams)) {
+ $cache = true;
+
+ foreach ($params as $param) {
+ if (!array_key_exists($param, $this->cacheParams)) {
+ $cache = false;
+ }
+ }
+
+ if ($cache) {
+ return true;
+ }
+ }
+
+ $query = "SELECT " . implode(',', $params) . " "
+ . "FROM accounts "
+ . "LEFT JOIN usrGroups ug ON account_userGroupId = usergroup_id "
+ . "LEFT JOIN usrData u1 ON account_userId = u1.user_id "
+ . "LEFT JOIN usrData u2 ON account_userEditId = u2.user_id "
+ . "LEFT JOIN customers ON account_customerId = customer_id "
+ . "WHERE account_id = " . (int)$this->accountId . " LIMIT 1";
+ $queryRes = DB::getResults($query, __FUNCTION__);
+
+ if ($queryRes === false) {
+ return false;
+ }
+
+ foreach ($queryRes as $param => $value) {
+ $this->cacheParams[$param] = $value;
+ }
+
+ return true;
+ }
+
+ /**
+ * @brief Crea una nueva cuenta en la BBDD
+ * @return bool
+ */
+ public function createAccount()
+ {
+ $query = "INSERT INTO accounts SET "
+ . "account_customerId = " . (int)$this->accountCustomerId . ","
+ . "account_categoryId = " . (int)$this->accountCategoryId . ","
+ . "account_name = '" . DB::escape($this->accountName) . "',"
+ . "account_login = '" . DB::escape($this->accountLogin) . "',"
+ . "account_url = '" . DB::escape($this->accountUrl) . "',"
+ . "account_pass = '$this->accountPass',"
+ . "account_IV = '" . DB::escape($this->accountIV) . "',"
+ . "account_notes = '" . DB::escape($this->accountNotes) . "',"
+ . "account_dateAdd = NOW(),"
+ . "account_userId = " . (int)$this->accountUserId . ","
+ . "account_userGroupId = " . (int)$this->accountUserGroupId . ","
+ . "account_otherUserEdit = " . (int)$this->accountOtherUserEdit . ","
+ . "account_otherGroupEdit = " . (int)$this->accountOtherGroupEdit;
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
+ }
+
+ $this->accountId = DB::$lastId;
+
+ $message['action'] = __FUNCTION__;
+
+ if (!SP_Groups::addGroupsForAccount($this->accountId, $this->accountUserGroupsId)) {
+ $message['text'][] = _('Error al actualizar los grupos secundarios');
+ SP_Log::wrLogInfo($message);
+ $message['text'] = array();
+ }
+
+ if (!SP_Users::addUsersForAccount($this->accountId, $this->accountUsersId)) {
+ $message['text'][] = _('Error al actualizar los usuarios de la cuenta');
+ SP_Log::wrLogInfo($message);
+ $message['text'] = array();
+ }
+
+ $accountInfo = array('customer_name');
+ $this->getAccountInfoById($accountInfo);
+
+ $message['action'] = _('Nueva Cuenta');
+ $message['text'][] = SP_Html::strongText(_('Cliente') . ": ") . $this->cacheParams['customer_name'];
+ $message['text'][] = SP_Html::strongText(_('Cuenta') . ": ") . "$this->accountName ($this->accountId)";
+
+ SP_Log::wrLogInfo($message);
+ SP_Common::sendEmail($message);
+
+ return true;
+ }
+
+ /**
+ * @brief Elimina los datos de una cuenta en la BBDD
+ * @return bool
+ */
+ public function deleteAccount()
+ {
+ // Guardamos una copia de la cuenta en el histórico
+ $this->addHistory(true) || die (_('ERROR: Error en la operación.'));
+
+ $accountInfo = array('account_name,customer_name');
+ $this->getAccountInfoById($accountInfo);
+
+ $message['action'] = _('Eliminar Cuenta');
+ $message['text'][] = SP_Html::strongText(_('Cliente') . ": ") . $this->cacheParams['customer_name'];
+ $message['text'][] = SP_Html::strongText(_('Cuenta') . ": ") . $this->cacheParams['account_name'] . " ($this->accountId)";
+
+ $query = "DELETE FROM accounts "
+ . "WHERE account_id = " . (int)$this->accountId . " LIMIT 1";
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
+ }
+
+ if (!SP_Groups::deleteGroupsForAccount($this->accountId)) {
+ $message['text'][] = _('Error al eliminar grupos asociados a la cuenta');
+ }
+
+ if (!SP_Users::deleteUsersForAccount($this->accountId)) {
+ $message['text'][] = _('Error al eliminar usuarios asociados a la cuenta');
+ }
+
+ if (!SP_Files::deleteAccountFiles($this->accountId)) {
+ $message['text'][] = _('Error al eliminar archivos asociados a la cuenta');
+ }
+
+ SP_Log::wrLogInfo($message);
+ SP_Common::sendEmail($message);
+
+ return true;
}
/**
* @brief Obtiene el listado del histórico de una cuenta
* @return array con los registros con id como clave y fecha - usuario como valor
- */
- public function getAccountHistoryList(){
+ */
+ public function getAccountHistoryList()
+ {
$query = "SELECT acchistory_id,"
- . "acchistory_dateEdit,"
- . "u1.user_login as user_edit,"
- . "u2.user_login as user_add,"
- . "acchistory_dateAdd "
- . "FROM accHistory "
- . "LEFT JOIN usrData u1 ON acchistory_userEditId = u1.user_id "
- . "LEFT JOIN usrData u2 ON acchistory_userId = u2.user_id "
- . "WHERE acchistory_accountId = ".$_SESSION["accParentId"]." "
- . "ORDER BY acchistory_id DESC";
-
- $queryRes = DB::getResults($query, __FUNCTION__, TRUE);
+ . "acchistory_dateEdit,"
+ . "u1.user_login as user_edit,"
+ . "u2.user_login as user_add,"
+ . "acchistory_dateAdd "
+ . "FROM accHistory "
+ . "LEFT JOIN usrData u1 ON acchistory_userEditId = u1.user_id "
+ . "LEFT JOIN usrData u2 ON acchistory_userId = u2.user_id "
+ . "WHERE acchistory_accountId = " . $_SESSION["accParentId"] . " "
+ . "ORDER BY acchistory_id DESC";
- if ( $queryRes === FALSE ){
- return FALSE;
+ $queryRes = DB::getResults($query, __FUNCTION__, true);
+
+ if ($queryRes === false) {
+ return false;
}
$arrHistory = array();
-
- foreach ( $queryRes as $history ){
- if ( $history->acchistory_dateEdit == '0000-00-00 00:00:00' ){
- $arrHistory[$history->acchistory_id] = $history->acchistory_dateAdd." - ".$history->user_add;
+
+ foreach ($queryRes as $history) {
+ if ($history->acchistory_dateEdit == '0000-00-00 00:00:00') {
+ $arrHistory[$history->acchistory_id] = $history->acchistory_dateAdd . " - " . $history->user_add;
} else {
- $arrHistory[$history->acchistory_id] = $history->acchistory_dateEdit." - ".$history->user_edit;
+ $arrHistory[$history->acchistory_id] = $history->acchistory_dateEdit . " - " . $history->user_edit;
}
}
return $arrHistory;
}
- /**
- * @brief Obtiene el listado de grupos secundarios de una cuenta
- * @return array con los registros con id de cuenta como clave e id de grupo como valor
- */
- public function getGroupsAccount (){
- $accId = ( $this->accountIsHistory && $this->accountParentId ) ? $this->accountParentId : $this->accountId;
-
- if ( ! is_array($this->accountCacheUserGroupsId) ){
- //error_log('Groups cache NO_INIT');
- $this->accountCacheUserGroupsId = array($accId => array());
- } else{
- if ( array_key_exists($accId, $this->accountCacheUserGroupsId) ){
- //error_log('Groups cache HIT');
- return $this->accountCacheUserGroupsId[$accId];
- }
- }
-
- //error_log('Groups cache MISS');
-
- $groups = SP_Groups::getGroupsForAccount($accId);
-
- if ( ! is_array($groups) ){
- return array();
- }
-
- foreach ( $groups as $group ){
- $this->accountCacheUserGroupsId[$accId][] = $group->accgroup_groupId;
- }
-
- return $this->accountCacheUserGroupsId[$accId];
- }
-
- /**
- * @brief Obtiene el listado usuarios con acceso a una cuenta
- * @return array con los registros con id de cuenta como clave e id de usuario como valor
- */
- public function getUsersAccount (){
- $accId = ( $this->accountIsHistory && $this->accountParentId ) ? $this->accountParentId : $this->accountId;
-
- if ( ! is_array($this->accountCacheUsersId) ){
- //error_log('Users cache MISS');
- $this->accountCacheUsersId = array($accId => array());
- } else{
- if ( array_key_exists($accId, $this->accountCacheUsersId) ){
- //error_log('Users cache HIT');
- return $this->accountCacheUsersId[$accId];
- }
- }
-
- $query = "SELECT accuser_userId "
- . "FROM accUsers "
- . "WHERE accuser_accountId = ".(int)$accId;
-
- $queryRes = DB::getResults($query, __FUNCTION__, TRUE);
-
- if ( $queryRes === FALSE ){
- return array();
- }
-
- foreach ( $queryRes as $users ){
- $this->accountCacheUsersId[$accId][] = $users->accuser_userId;
- }
-
- return $this->accountCacheUsersId[$accId];
- }
-
- /**
- * @brief Obtiene el listado con el nombre de los usuaios de una cuenta
- * @return array con los nombres de los usuarios ordenados
- */
- public static function getAccountUsersName ($accountId){
- $query = "SELECT user_name "
- . "FROM accUsers "
- . "JOIN usrData ON accuser_userId = user_id "
- . "WHERE accuser_accountId = ".(int)$accountId;
-
- $queryRes = DB::getResults($query, __FUNCTION__);
-
- if ( $queryRes === FALSE ){
- return FALSE;
- }
-
- if (!is_array($queryRes)) {
- return FALSE;
- }
-
- foreach ( $queryRes as $users ){
- $usersName[] = $users->user_name;
- }
-
- sort($usersName, SORT_STRING);
-
- return $usersName;
- }
-
/**
* @brief Incrementa el contador de visitas de una cuenta en la BBDD
* @return bool
- */
- public function incrementViewCounter(){
+ */
+ public function incrementViewCounter()
+ {
$query = "UPDATE accounts "
- . "SET account_countView = (account_countView + 1) "
- . "WHERE account_id = ".(int)$this->accountId;
-
- if ( DB::doQuery($query, __FUNCTION__) === FALSE ){
- return FALSE;
+ . "SET account_countView = (account_countView + 1) "
+ . "WHERE account_id = " . (int)$this->accountId;
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
- return TRUE;
+ return true;
}
/**
* @brief Incrementa el contador de vista de clave de una cuenta en la BBDD
* @return bool
- */
- public function incrementDecryptCounter(){
+ */
+ public function incrementDecryptCounter()
+ {
$query = "UPDATE accounts SET account_countDecrypt = (account_countDecrypt + 1) "
- . "WHERE account_id = ".(int)$this->accountId;
-
- if ( DB::doQuery($query, __FUNCTION__) === FALSE ){
- return FALSE;
+ . "WHERE account_id = " . (int)$this->accountId;
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
- return TRUE;
+ return true;
}
/**
* @brief Obtiene el número de cuentas que un usuario puede ver
* @return int con el número de registros
- */
- public function getAccountMax(){
+ */
+ public function getAccountMax()
+ {
$userGroupId = $_SESSION["ugroup"];
$userId = $_SESSION["uid"];
$userIsAdminApp = $_SESSION['uisadminapp'];
$userIsAdminAcc = $_SESSION['uisadminacc'];
- if ( ! $userIsAdminApp && ! $userIsAdminAcc ){
+ if (!$userIsAdminApp && !$userIsAdminAcc) {
$query = "SELECT COUNT(DISTINCT account_id) as numacc "
- . "FROM accounts "
- . "LEFT JOIN accGroups ON account_id = accgroup_accountId "
- . "WHERE account_userGroupId = ".(int)$userGroupId." "
- . "OR account_userId = ".(int)$userId." "
- . "OR accgroup_groupId = ".(int)$userGroupId;
+ . "FROM accounts "
+ . "LEFT JOIN accGroups ON account_id = accgroup_accountId "
+ . "WHERE account_userGroupId = " . (int)$userGroupId . " "
+ . "OR account_userId = " . (int)$userId . " "
+ . "OR accgroup_groupId = " . (int)$userGroupId;
} else {
$query = "SELECT COUNT(account_id) as numacc FROM accounts";
}
$queryRes = DB::getResults($query, __FUNCTION__);
- if ( $queryRes === FALSE ){
- return FALSE;
+ if ($queryRes === false) {
+ return false;
}
return $queryRes->numacc;
}
- /**
- * @brief Obtener los datos relativos a la clave de todas las cuentas
- * @return array con los datos de la clave
- */
- private function getAccountsPassData(){
- $query = "SELECT account_id,"
- . "account_pass,"
- . "account_IV "
- . "FROM accounts";
- $queryRes = DB::getResults($query, __FUNCTION__, TRUE);
-
- if ( $queryRes === FALSE ){
- return FALSE;
- }
-
- return $queryRes;
- }
-
- /**
- * @brief Obtener los datos relativo a la clave de todas las cuentas del histórico
- * @return array con los datos de la clave
- */
- private function getAccountsHistoryPassData(){
- $query = "SELECT acchistory_id,"
- . "acchistory_pass,"
- . "acchistory_IV "
- . "FROM accHistory";
- $queryRes = DB::getResults($query, __FUNCTION__, TRUE);
-
- if ( $queryRes === FALSE ){
- return FALSE;
- }
-
- return $queryRes;
- }
-
/**
* @brief Actualiza las claves de todas las cuentas con la nueva clave maestra
* @param string $currentMasterPass con la clave maestra actual
* @param string $newMasterPass con la nueva clave maestra
* @return bool
*/
- public function updateAllAccountsMPass($currentMasterPass, $newMasterPass){
+ public function updateAllAccountsMPass($currentMasterPass, $newMasterPass)
+ {
$accountsOk = array();
$userId = $_SESSION["uid"];
$errorCount = 0;
- $demoEnabled = SP_Config::getValue('demoenabled',0);
+ $demoEnabled = SP_Config::getValue('demoenabled', 0);
$message['action'] = _('Actualizar Clave Maestra');
$message['text'][] = _('Inicio');
-
- SP_Common::wrLogInfo($message);
-
+
+ SP_Log::wrLogInfo($message);
+
// Limpiar 'text' para los próximos mensajes
$message['text'] = array();
-
+
$crypt = new SP_Crypt();
-
- if ( !SP_Crypt::checkCryptModule() ) {
+
+ if (!SP_Crypt::checkCryptModule()) {
$message['text'][] = _('Error en el módulo de encriptación');
- SP_Common::wrLogInfo($message);
- return FALSE;
+ SP_Log::wrLogInfo($message);
+ return false;
}
$accountsPass = $this->getAccountsPassData();
-
- if ( ! $accountsPass ){
+
+ if (!$accountsPass) {
$message['text'][] = _('Error al obtener las claves de las cuentas');
- SP_Common::wrLogInfo($message);
- return FALSE;
+ SP_Log::wrLogInfo($message);
+ return false;
}
-
- foreach ( $accountsPass as $account ){
+
+ foreach ($accountsPass as $account) {
$this->accountId = $account->account_id;
$this->accountUserEditId = $userId;
-
+
// No realizar cambios si está en modo demo
- if ( $demoEnabled ){
+ if ($demoEnabled) {
$accountsOk[] = $this->accountId;
continue;
}
-
+
$decryptedPass = $crypt->decrypt($account->account_pass, $currentMasterPass, $account->account_IV);
- $this->accountPass = $crypt->mkEncrypt($decryptedPass,$newMasterPass);
+ $this->accountPass = $crypt->mkEncrypt($decryptedPass, $newMasterPass);
$this->accountIV = $crypt->strInitialVector;
-
- if ( $this->accountPass === FALSE ){
+
+ if ($this->accountPass === false) {
$errorCount++;
continue;
}
-
- if ( ! $this->updateAccountPass(TRUE) ){
+
+ if (!$this->updateAccountPass(true)) {
$errorCount++;
- $message['text'][] = _('Fallo al actualizar la clave de la cuenta')."(".$this->accountId.")";
+ $message['text'][] = _('Fallo al actualizar la clave de la cuenta') . "(" . $this->accountId . ")";
}
$accountsOk[] = $this->accountId;
}
-
+
// Vaciar el array de mensaje de log
- if ( count($message['text']) > 0 ){
- SP_Common::wrLogInfo($message);
+ if (count($message['text']) > 0) {
+ SP_Log::wrLogInfo($message);
$message['text'] = array();
}
-
- if ( $accountsOk ) {
- $message['text'][] = _('Cuentas actualizadas:').": ".implode(',',$accountsOk);
- SP_Common::wrLogInfo($message);
+
+ if ($accountsOk) {
+ $message['text'][] = _('Cuentas actualizadas:') . ": " . implode(',', $accountsOk);
+ SP_Log::wrLogInfo($message);
$message['text'] = array();
}
-
+
$message['text'][] = _('Fin');
- SP_Common::wrLogInfo($message);
+ SP_Log::wrLogInfo($message);
+ SP_Common::sendEmail($message);
- if ( $errorCount > 0 ){
- return FALSE;
+ if ($errorCount > 0) {
+ return false;
}
- return TRUE;
+ return true;
+ }
+
+ /**
+ * @brief Obtener los datos relativos a la clave de todas las cuentas
+ * @return array con los datos de la clave
+ */
+ private function getAccountsPassData()
+ {
+ $query = "SELECT account_id,"
+ . "account_pass,"
+ . "account_IV "
+ . "FROM accounts";
+ $queryRes = DB::getResults($query, __FUNCTION__, true);
+
+ if ($queryRes === false) {
+ return false;
+ }
+
+ return $queryRes;
+ }
+
+ /**
+ * @brief Actualiza la clave de una cuenta en la BBDD
+ * @param bool $isMassive para no actualizar el histórico ni enviar mensajes
+ * @return bool
+ */
+ public function updateAccountPass($isMassive = false)
+ {
+ $message['action'] = __FUNCTION__;
+
+ // No actualizar el histórico si es por cambio de clave maestra
+ if (!$isMassive) {
+ // Guardamos una copia de la cuenta en el histórico
+ if (!$this->addHistory($this->accountId, $this->accountUserEditId, false)) {
+ $message['text'][] = _('Error al actualizar el historial');
+ SP_Log::wrLogInfo($message);
+ return false;
+ }
+ }
+
+ $query = "UPDATE accounts SET "
+ . "account_pass = '" . DB::escape($this->accountPass) . "',"
+ . "account_IV = '" . DB::escape($this->accountIV) . "',"
+ . "account_userEditId = " . (int)$this->accountUserEditId . ","
+ . "account_dateEdit = NOW() "
+ . "WHERE account_id = " . (int)$this->accountId;
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
+ }
+
+ // No escribir en el log ni enviar correos si la actualización es
+ // por cambio de clave maestra...
+ if (!$isMassive) {
+ $accountInfo = array('customer_name', 'account_name');
+ $this->getAccountInfoById($accountInfo);
+
+ $message['action'] = _('Modificar Clave');
+ $message['text'][] = SP_Html::strongText(_('Cliente') . ": ") . $this->cacheParams['customer_name'];
+ $message['text'][] = SP_Html::strongText(_('Cuenta') . ": ") . $this->cacheParams['account_name'] . " ($this->accountId)";
+
+ SP_Log::wrLogInfo($message);
+ SP_Common::sendEmail($message);
+ }
+
+ return true;
}
/**
* @brief Actualiza las claves de todas las cuentas en el histórico con la nueva clave maestra
* @param string $currentMasterPass con la clave maestra actual
* @param string $newMasterPass con la nueva clave maestra
- * @param string $newHash con el nuevo hash de la clave maestra
+ * @param string $newHash con el nuevo hash de la clave maestra
* @return bool
*/
- public function updateAllAccountsHistoryMPass($currentMasterPass, $newMasterPass, $newHash){
+ public function updateAllAccountsHistoryMPass($currentMasterPass, $newMasterPass, $newHash)
+ {
$idOk = array();
$errorCount = 0;
- $demoEnabled = SP_Config::getValue('demoenabled',0);
+ $demoEnabled = SP_Config::getValue('demoenabled', 0);
$message['action'] = _('Actualizar Clave Maestra (H)');
$message['text'][] = _('Inicio');
-
- SP_Common::wrLogInfo($message);
-
+
+ SP_Log::wrLogInfo($message);
+
// Limpiar 'text' para los próximos mensajes
$message['text'] = array();
-
+
$crypt = new SP_Crypt();
-
- if ( !SP_Crypt::checkCryptModule() ) {
+
+ if (!SP_Crypt::checkCryptModule()) {
$message['text'][] = _('Error en el módulo de encriptación');
- SP_Common::wrLogInfo($message);
- return FALSE;
+ SP_Log::wrLogInfo($message);
+ return false;
}
$accountsPass = $this->getAccountsHistoryPassData();
-
- if ( ! $accountsPass ){
+
+ if (!$accountsPass) {
$message['text'][] = _('Error al obtener las claves de las cuentas');
- SP_Common::wrLogInfo($message);
- return FALSE;
+ SP_Log::wrLogInfo($message);
+ return false;
}
-
- foreach ( $accountsPass as $account ){
+
+ foreach ($accountsPass as $account) {
// No realizar cambios si está en modo demo
- if ( $demoEnabled ){
+ if ($demoEnabled) {
$idOk[] = $account->acchistory_id;
continue;
}
- if ( ! $this->checkAccountMPass($account->acchistory_id) ){
+ if (!$this->checkAccountMPass($account->acchistory_id)) {
$errorCount++;
- $message['text'][] = _('La clave maestra del registro no coincide')." (".$account->acchistory_id.")";
+ $message['text'][] = _('La clave maestra del registro no coincide') . " (" . $account->acchistory_id . ")";
continue;
}
-
+
$decryptedPass = $crypt->decrypt($account->acchistory_pass, $currentMasterPass, $account->acchistory_IV);
-
- $this->accountPass = $crypt->mkEncrypt($decryptedPass,$newMasterPass);
+
+ $this->accountPass = $crypt->mkEncrypt($decryptedPass, $newMasterPass);
$this->accountIV = $crypt->strInitialVector;
-
- if ( $this->accountPass === FALSE ){
+
+ if ($this->accountPass === false) {
$errorCount++;
continue;
}
-
- if ( ! $this->updateAccountHistoryPass($account->acchistory_id, $newHash) ){
+
+ if (!$this->updateAccountHistoryPass($account->acchistory_id, $newHash)) {
$errorCount++;
- $message['text'][] = _('Fallo al actualizar la clave del histórico')." (".$account->acchistory_id.")";
+ $message['text'][] = _('Fallo al actualizar la clave del histórico') . " (" . $account->acchistory_id . ")";
}
-
+
$idOk[] = $account->acchistory_id;
}
// Vaciar el array de mensaje de log
- if ( count($message['text']) > 0 ){
- SP_Common::wrLogInfo($message);
+ if (count($message['text']) > 0) {
+ SP_Log::wrLogInfo($message);
$message['text'] = array();
}
-
- if ( $idOk ) {
- $message['text'][] = _('Registros actualizados:').": ".implode(',',$idOk);
- SP_Common::wrLogInfo($message);
+
+ if ($idOk) {
+ $message['text'][] = _('Registros actualizados:') . ": " . implode(',', $idOk);
+ SP_Log::wrLogInfo($message);
$message['text'] = array();
}
-
+
$message['text'][] = _('Fin');
- SP_Common::wrLogInfo($message);
+ SP_Log::wrLogInfo($message);
- if ( $errorCount > 0 ){
- return FALSE;
+ if ($errorCount > 0) {
+ return false;
}
- return TRUE;
+ return true;
}
-
+
+ /**
+ * @brief Obtener los datos relativo a la clave de todas las cuentas del histórico
+ * @return array con los datos de la clave
+ */
+ private function getAccountsHistoryPassData()
+ {
+ $query = "SELECT acchistory_id,"
+ . "acchistory_pass,"
+ . "acchistory_IV "
+ . "FROM accHistory";
+ $queryRes = DB::getResults($query, __FUNCTION__, true);
+
+ if ($queryRes === false) {
+ return false;
+ }
+
+ return $queryRes;
+ }
+
/**
* @brief Comprueba el hash de la clave maestra del registro de histórico de una cuenta
* @param int $id opcional, con el Id del registro a comprobar
* @return bool
*/
- public function checkAccountMPass($id = NULL){
- if ( is_null($id) ){
+ public function checkAccountMPass($id = NULL)
+ {
+ if (is_null($id)) {
$id = $this->accountId;
}
-
+
$query = "SELECT acchistory_mPassHash "
- . "FROM accHistory "
- . "WHERE acchistory_id = ".(int)$id;
+ . "FROM accHistory "
+ . "WHERE acchistory_id = " . (int)$id;
$queryRes = DB::getResults($query, __FUNCTION__);
- if ( $queryRes === FALSE ){
- return FALSE;
+ if ($queryRes === false) {
+ return false;
}
- if ( $queryRes->acchistory_mPassHash != SP_Config::getConfigValue('masterPwd') ){
- return FALSE;
+ if ($queryRes->acchistory_mPassHash != SP_Config::getConfigValue('masterPwd')) {
+ return false;
}
- return TRUE;
+ return true;
}
/**
- * @brief Obtener los datos de una cuenta con el id
- * @param array $params con los campos de la BBDD a obtener
+ * @brief Actualiza la clave del histórico de una cuenta en la BBDD
+ * @param int $id con el id del registro a actualizar
+ * @param string $newHash con el hash de la clave maestra
* @return bool
- *
- * Se guardan los datos en la variable $cacheParams de la clase para consultarlos
- * posteriormente.
*/
- private function getAccountInfoById($params) {
- if (!is_array($params)) {
- return FALSE;
+ public function updateAccountHistoryPass($id, $newHash)
+ {
+ $query = "UPDATE accHistory SET "
+ . "acchistory_pass = '" . DB::escape($this->accountPass) . "',"
+ . "acchistory_IV = '" . DB::escape($this->accountIV) . "',"
+ . "acchistory_mPassHash = '" . DB::escape($newHash) . "' "
+ . "WHERE acchistory_id = " . (int)$id;
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
- if (is_array($this->cacheParams)) {
- $cache = TRUE;
-
- foreach ($params as $param) {
- if (!array_key_exists($param, $this->cacheParams)) {
- $cache = FALSE;
- }
- }
-
- if ($cache) {
- return TRUE;
- }
- }
-
- $query = "SELECT " . implode(',', $params) . " "
- . "FROM accounts "
- . "LEFT JOIN usrGroups ug ON account_userGroupId = usergroup_id "
- . "LEFT JOIN usrData u1 ON account_userId = u1.user_id "
- . "LEFT JOIN usrData u2 ON account_userEditId = u2.user_id "
- . "LEFT JOIN customers ON account_customerId = customer_id "
- . "WHERE account_id = " . (int) $this->accountId . " LIMIT 1";
- $queryRes = DB::getResults($query, __FUNCTION__);
-
- if ($queryRes === FALSE) {
- return FALSE;
- }
-
- foreach ($queryRes as $param => $value) {
- $this->cacheParams[$param] = $value;
- }
-
- return TRUE;
+ return true;
}
/**
* @brief Calcular el hash de los datos de una cuenta
* @return string con el hash
- *
+ *
* Esta función se utiliza para verificar si los datos de un formulario han sido cambiados
* con respecto a los guardados
*/
- public function calcChangesHash(){
+ public function calcChangesHash()
+ {
$groups = 0;
$users = 0;
-
- if ( is_array($this->accountUserGroupsId)){
+
+ if (is_array($this->accountUserGroupsId)) {
$groups = implode($this->accountUserGroupsId);
- } elseif (is_array($this->accountCacheUserGroupsId) ){
- foreach ($this->accountCacheUserGroupsId as $id => $group){
- if (is_array($group) ){
+ } elseif (is_array($this->accountCacheUserGroupsId)) {
+ foreach ($this->accountCacheUserGroupsId as $group) {
+ if (is_array($group)) {
// Ordenar el array para que el hash sea igual
sort($group, SORT_NUMERIC);
$groups = implode($group);
}
- }
+ }
}
-
- if ( is_array($this->accountUsersId)){
+
+ if (is_array($this->accountUsersId)) {
$users = implode($this->accountUsersId);
- } elseif (is_array($this->accountCacheUsersId) ){
- foreach ($this->accountCacheUsersId as $id => $user){
- if (is_array($user) ){
+ } elseif (is_array($this->accountCacheUsersId)) {
+ foreach ($this->accountCacheUsersId as $user) {
+ if (is_array($user)) {
// Ordenar el array para que el hash sea igual
sort($user, SORT_NUMERIC);
$users = implode($user);
}
- }
+ }
}
-
- return md5($this->accountName.
- $this->accountCategoryId.
- $this->accountCustomerId.
- $groups.
- $users.
- $this->accountLogin.
- $this->accountUrl.
- $this->accountNotes);
+
+ if ( ! empty($this->accountModHash) ){
+ $hashItems = $this->accountModHash.(int)$users.(int)$groups;
+ //error_log("HASH MySQL: ".$hashItems);
+ } else{
+ $hashItems = $this->accountName.
+ $this->accountCategoryId.
+ $this->accountCustomerId.
+ $this->accountLogin.
+ $this->accountUrl.
+ $this->accountNotes.
+ (int)$users.
+ (int)$groups;
+ //error_log("HASH PHP: ".$hashItems);
+ }
+
+ return md5($hashItems);
}
-
+
/**
* @brief Devolver datos de la cuenta para comprobación de accesos
* @return array con los datos de la cuenta
*/
- public function getAccountDataForACL(){
+ public function getAccountDataForACL()
+ {
return array(
'id' => $this->accountId,
'user_id' => $this->accountUserId,
@@ -1118,4 +1083,72 @@ class SP_Account {
'othergroup_edit' => $this->accountOtherGroupEdit
);
}
+
+ /**
+ * @brief Obtiene el listado usuarios con acceso a una cuenta
+ * @return array con los registros con id de cuenta como clave e id de usuario como valor
+ */
+ public function getUsersAccount()
+ {
+ $accId = ($this->accountIsHistory && $this->accountParentId) ? $this->accountParentId : $this->accountId;
+
+ if (!is_array($this->accountCacheUsersId)) {
+ //error_log('Users cache MISS');
+ $this->accountCacheUsersId = array($accId => array());
+ } else {
+ if (array_key_exists($accId, $this->accountCacheUsersId)) {
+ //error_log('Users cache HIT');
+ return $this->accountCacheUsersId[$accId];
+ }
+ }
+
+ $query = "SELECT accuser_userId "
+ . "FROM accUsers "
+ . "WHERE accuser_accountId = " . (int)$accId;
+
+ $queryRes = DB::getResults($query, __FUNCTION__, true);
+
+ if ($queryRes === false) {
+ return array();
+ }
+
+ foreach ($queryRes as $users) {
+ $this->accountCacheUsersId[$accId][] = $users->accuser_userId;
+ }
+
+ return $this->accountCacheUsersId[$accId];
+ }
+
+ /**
+ * @brief Obtiene el listado de grupos secundarios de una cuenta
+ * @return array con los registros con id de cuenta como clave e id de grupo como valor
+ */
+ public function getGroupsAccount()
+ {
+ $accId = ($this->accountIsHistory && $this->accountParentId) ? $this->accountParentId : $this->accountId;
+
+ if (!is_array($this->accountCacheUserGroupsId)) {
+ //error_log('Groups cache NO_INIT');
+ $this->accountCacheUserGroupsId = array($accId => array());
+ } else {
+ if (array_key_exists($accId, $this->accountCacheUserGroupsId)) {
+ //error_log('Groups cache HIT');
+ return $this->accountCacheUserGroupsId[$accId];
+ }
+ }
+
+ //error_log('Groups cache MISS');
+
+ $groups = SP_Groups::getGroupsForAccount($accId);
+
+ if (!is_array($groups)) {
+ return array();
+ }
+
+ foreach ($groups as $group) {
+ $this->accountCacheUserGroupsId[$accId][] = $group->accgroup_groupId;
+ }
+
+ return $this->accountCacheUserGroupsId[$accId];
+ }
}
\ No newline at end of file
diff --git a/inc/acl.class.php b/inc/acl.class.php
index 9c35f8b8..9a5c1e45 100644
--- a/inc/acl.class.php
+++ b/inc/acl.class.php
@@ -2,11 +2,11 @@
/**
* sysPass
- *
+ *
* @author nuxsmin
* @link http://syspass.org
- * @copyright 2012 Rubén Domínguez nuxsmin@syspass.org
- *
+ * @copyright 2012-2014 Rubén Domínguez nuxsmin@syspass.org
+ *
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
@@ -23,13 +23,15 @@
* along with sysPass. If not, see .
*
*/
+
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
/**
* Esta clase es la encargada de calcular las access lists de acceso a usuarios.
*/
-class SP_ACL {
-
+class SP_ACL
+{
+
static $accountCacheUserGroupsId;
/**
@@ -37,15 +39,16 @@ class SP_ACL {
* @param string $strAction con el nombre de la acción
* @param int $userId opcional, con el Id del usuario
* @return bool
- *
+ *
* Esta función comprueba los permisos del usuario para realizar una acción.
* Si los permisos ya han sido obtenidos desde la BBDD, se utiliza el objeto creado
* en la variable de sesión.
*/
- public static function checkUserAccess($strAction, $userId = 0) {
+ public static function checkUserAccess($strAction, $userId = 0)
+ {
// Comprobamos si la cache de permisos está inicializada
if (!isset($_SESSION["usrprofile"]) || !is_object($_SESSION["usrprofile"])) {
- return FALSE;
+ return false;
}
$blnUIsAdminApp = $_SESSION["uisadminapp"];
@@ -54,121 +57,122 @@ class SP_ACL {
switch ($strAction) {
case "accview":
- return ( $blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pView );
+ return ($blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pView);
case "accviewpass":
- return ( $blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pViewPass );
+ return ($blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pViewPass);
case "accviewhistory":
- return ( $blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pViewHistory );
+ return ($blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pViewHistory);
case "accedit":
- return ( $blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pEdit );
+ return ($blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pEdit);
case "acceditpass":
- return ( $blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pEditPass || $userId == $_SESSION["uid"] );
+ return ($blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pEditPass || $userId == $_SESSION["uid"]);
case "accnew":
- return ( $blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pAdd );
+ return ($blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pAdd);
case "acccopy":
- return ( $blnUIsAdminApp || $blnUIsAdminAcc || ($profile->userProfile_pAdd && $profile->userProfile_pView) );
+ return ($blnUIsAdminApp || $blnUIsAdminAcc || ($profile->userProfile_pAdd && $profile->userProfile_pView));
case "accdelete":
- return ( $blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pDelete );
+ return ($blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pDelete);
case "accfiles":
- return ( $blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pFiles );
+ return ($blnUIsAdminApp || $blnUIsAdminAcc || $profile->userProfile_pFiles);
case "appmgmtmenu":
- return ( $blnUIsAdminApp || $profile->userProfile_pAppMgmtMenu );
+ return ($blnUIsAdminApp || $profile->userProfile_pAppMgmtMenu);
case "configmenu":
- return ( $blnUIsAdminApp || $profile->userProfile_pConfigMenu );
+ return ($blnUIsAdminApp || $profile->userProfile_pConfigMenu);
case "config":
- return ( $blnUIsAdminApp || $profile->userProfile_pConfig );
+ return ($blnUIsAdminApp || $profile->userProfile_pConfig);
case "categories":
- return ( $blnUIsAdminApp || $profile->userProfile_pAppMgmtCategories );
+ return ($blnUIsAdminApp || $profile->userProfile_pAppMgmtCategories);
case "customers":
- return ( $blnUIsAdminApp || $profile->userProfile_pAppMgmtCustomers );
+ return ($blnUIsAdminApp || $profile->userProfile_pAppMgmtCustomers);
case "masterpass":
- return ( $blnUIsAdminApp || $profile->userProfile_pConfigMasterPass );
+ return ($blnUIsAdminApp || $profile->userProfile_pConfigMasterPass);
case "backup":
- return ( $blnUIsAdminApp || $profile->userProfile_pConfigBackup );
+ return ($blnUIsAdminApp || $profile->userProfile_pConfigBackup);
case "usersmenu":
- return ( $blnUIsAdminApp || $profile->userProfile_pUsersMenu );
+ return ($blnUIsAdminApp || $profile->userProfile_pUsersMenu);
case "users":
- return ( $blnUIsAdminApp || $profile->userProfile_pUsers );
+ return ($blnUIsAdminApp || $profile->userProfile_pUsers);
case "groups":
- return ( $blnUIsAdminApp || $profile->userProfile_pGroups );
+ return ($blnUIsAdminApp || $profile->userProfile_pGroups);
case "profiles":
- return ( $blnUIsAdminApp || $profile->userProfile_pProfiles );
+ return ($blnUIsAdminApp || $profile->userProfile_pProfiles);
case "eventlog":
- return ( $blnUIsAdminApp || $profile->userProfile_pEventlog );
+ return ($blnUIsAdminApp || $profile->userProfile_pEventlog);
}
$message['action'][] = __FUNCTION__;
$message['text'][] = _('Denegado acceso a') . " '" . $strAction . "'";
- SP_Common::wrLogInfo($message);
+ SP_Log::wrLogInfo($message);
- return FALSE;
+ return false;
}
-
+
/**
* @brief Comprueba los permisos de acceso a una cuenta
* @param string $action con la acción realizada
* @param array $accountData con los datos de la cuenta a verificar
* @return bool
- */
- public static function checkAccountAccess($action, $accountData){
+ */
+ public static function checkAccountAccess($action, $accountData)
+ {
$userGroupId = $_SESSION["ugroup"];
$userId = $_SESSION["uid"];
$userIsAdminApp = $_SESSION["uisadminapp"];
$userIsAdminAcc = $_SESSION["uisadminacc"];
-
- switch ($action){
+
+ switch ($action) {
case "accview":
- return ( $userId == $accountData['user_id']
- || $userGroupId == $accountData['group_id']
- || in_array($userId, $accountData['users_id'])
- || in_array($userGroupId, $accountData['groups_id'])
- || $userIsAdminApp
- || $userIsAdminAcc );
+ return ($userId == $accountData['user_id']
+ || $userGroupId == $accountData['group_id']
+ || in_array($userId, $accountData['users_id'])
+ || in_array($userGroupId, $accountData['groups_id'])
+ || $userIsAdminApp
+ || $userIsAdminAcc);
case "accviewpass":
- return ( $userId == $accountData['user_id']
- || $userGroupId == $accountData['group_id']
- || in_array($userId, $accountData['users_id'])
- || in_array($userGroupId, $accountData['groups_id'])
- || $userIsAdminApp
- || $userIsAdminAcc );
+ return ($userId == $accountData['user_id']
+ || $userGroupId == $accountData['group_id']
+ || in_array($userId, $accountData['users_id'])
+ || in_array($userGroupId, $accountData['groups_id'])
+ || $userIsAdminApp
+ || $userIsAdminAcc);
case "accviewhistory":
- return ( $userId == $accountData['user_id']
- || $userGroupId == $accountData['group_id']
- || in_array($userId, $accountData['users_id'])
- || in_array($userGroupId, $accountData['groups_id'])
- || $userIsAdminApp
- || $userIsAdminAcc );
+ return ($userId == $accountData['user_id']
+ || $userGroupId == $accountData['group_id']
+ || in_array($userId, $accountData['users_id'])
+ || in_array($userGroupId, $accountData['groups_id'])
+ || $userIsAdminApp
+ || $userIsAdminAcc);
case "accedit":
- return ( $userId == $accountData['user_id']
- || $userGroupId == $accountData['group_id']
- || (in_array($userId, $accountData['users_id']) && $accountData['otheruser_edit'])
- || (in_array($userGroupId, $accountData['groups_id']) && $accountData['othergroup_edit'])
- || $userIsAdminApp
- || $userIsAdminAcc );
+ return ($userId == $accountData['user_id']
+ || $userGroupId == $accountData['group_id']
+ || (in_array($userId, $accountData['users_id']) && $accountData['otheruser_edit'])
+ || (in_array($userGroupId, $accountData['groups_id']) && $accountData['othergroup_edit'])
+ || $userIsAdminApp
+ || $userIsAdminAcc);
case "accdelete":
- return ( $userId == $accountData['user_id']
- || $userGroupId == $accountData['group_id']
- || (in_array($userId, $accountData['users_id']) && $accountData['otheruser_edit'])
- || (in_array($userGroupId, $accountData['groups_id']) && $accountData['othergroup_edit'])
- || $userIsAdminApp
- || $userIsAdminAcc );
+ return ($userId == $accountData['user_id']
+ || $userGroupId == $accountData['group_id']
+ || (in_array($userId, $accountData['users_id']) && $accountData['otheruser_edit'])
+ || (in_array($userGroupId, $accountData['groups_id']) && $accountData['othergroup_edit'])
+ || $userIsAdminApp
+ || $userIsAdminAcc);
case "acceditpass":
- return ( $userId == $accountData['user_id']
- || $userGroupId == $accountData['group_id']
- || (in_array($userId, $accountData['users_id']) && $accountData['otheruser_edit'])
- || (in_array($userGroupId, $accountData['groups_id']) && $accountData['othergroup_edit'])
- || $userIsAdminApp
- || $userIsAdminAcc );
+ return ($userId == $accountData['user_id']
+ || $userGroupId == $accountData['group_id']
+ || (in_array($userId, $accountData['users_id']) && $accountData['otheruser_edit'])
+ || (in_array($userGroupId, $accountData['groups_id']) && $accountData['othergroup_edit'])
+ || $userIsAdminApp
+ || $userIsAdminAcc);
case "acccopy":
- return ( $userId == $accountData['user_id']
- || $userGroupId == $accountData['group_id']
- || in_array($userId, $accountData['users_id'])
- || in_array($userGroupId, $accountData['groups_id'])
- || $userIsAdminApp
- || $userIsAdminAcc );
+ return ($userId == $accountData['user_id']
+ || $userGroupId == $accountData['group_id']
+ || in_array($userId, $accountData['users_id'])
+ || in_array($userGroupId, $accountData['groups_id'])
+ || $userIsAdminApp
+ || $userIsAdminAcc);
}
-
- return FALSE;
+
+ return false;
}
}
\ No newline at end of file
diff --git a/inc/auth.class.php b/inc/auth.class.php
index eb4d2bb1..981d9a9d 100644
--- a/inc/auth.class.php
+++ b/inc/auth.class.php
@@ -2,11 +2,11 @@
/**
* sysPass
- *
+ *
* @author nuxsmin
* @link http://syspass.org
- * @copyright 2012 Rubén Domínguez nuxsmin@syspass.org
- *
+ * @copyright 2012-2014 Rubén Domínguez nuxsmin@syspass.org
+ *
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
@@ -23,13 +23,14 @@
* along with sysPass. If not, see .
*
*/
+
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
/**
* Esta clase es la encargada de realizar la autentificación de usuarios de sysPass.
*/
-class SP_Auth {
-
+class SP_Auth
+{
static $userName;
static $userEmail;
@@ -39,12 +40,13 @@ class SP_Auth {
* @param string $userPass con la clave del usuario
* @return bool
*/
- public static function authUserLDAP($userLogin, $userPass) {
- if (!SP_Util::ldapIsAvailable() || !SP_Config::getValue('ldapenabled', FALSE) || !SP_LDAP::checkLDAPParams()) {
- return FALSE;
+ public static function authUserLDAP($userLogin, $userPass)
+ {
+ if (!SP_Util::ldapIsAvailable() || !SP_Config::getValue('ldapenabled', false) || !SP_LDAP::checkLDAPParams()) {
+ return false;
}
- $ldapAccess = FALSE;
+ $ldapAccess = false;
$message['action'] = __FUNCTION__;
// Conectamos al servidor realizamos la conexión con el usuario proxy
@@ -53,7 +55,7 @@ class SP_Auth {
SP_LDAP::ldapBind();
SP_LDAP::getUserDN($userLogin);
} catch (Exception $e) {
- return FALSE;
+ return false;
}
$userDN = SP_LDAP::$ldapSearchData[0]['dn'];
@@ -77,7 +79,7 @@ class SP_Auth {
// Comprobamos si la cuenta está bloqueada o expirada
if (isset($attribs['expire']) && $attribs['expire'] > 0) {
- return FALSE;
+ return false;
}
// Comprobamos que el usuario está en el grupo indicado buscando en los atributos del usuario
@@ -90,101 +92,110 @@ class SP_Auth {
// Comprobamos que el usuario está en el grupo indicado
if (self::checkLDAPGroup($group)) {
- $ldapAccess = TRUE;
+ $ldapAccess = true;
break;
}
}
} else {
$ldapAccess = self::checkLDAPGroup($attribs['group']);
}
- // Comprobamos que el usuario está en el grupo indicado buscando en los atributos del grupo
+ // Comprobamos que el usuario está en el grupo indicado buscando en los atributos del grupo
} else {
$ldapAccess = SP_LDAP::searchUserInGroup($userDN);
}
- if ($ldapAccess == FALSE) {
+ if ($ldapAccess == false) {
$message['text'][] = _('El usuario no tiene grupos asociados');
- SP_Common::wrLogInfo($message);
+ SP_Log::wrLogInfo($message);
}
-
+
self::$userName = $attribs['name'];
self::$userEmail = $attribs['mail'];
return $ldapAccess;
}
- /**
- * @brief Autentificación de usuarios con MySQL
- * @param string $userLogin con el login del usuario
- * @param string $userPass con la clave del usuario
- * @return bool
- *
- * Esta función comprueba la clave del usuario. Si el usuario necesita ser migrado desde phpPMS,
- * se ejecuta el proceso para actualizar la clave.
- */
- public static function authUserMySQL($userLogin, $userPass) {
- if (SP_Users::checkUserIsMigrate($userLogin)) {
- if (!SP_Users::migrateUser($userLogin, $userPass)) {
- return FALSE;
- }
- }
-
- $query = "SELECT user_login,"
- . "user_pass "
- . "FROM usrData "
- . "WHERE user_login = '" . DB::escape($userLogin) . "' "
- . "AND user_isMigrate = 0 "
- . "AND user_pass = SHA1(CONCAT(user_hashSalt,'" . DB::escape($userPass) . "')) LIMIT 1";
-
- if (DB::doQuery($query, __FUNCTION__) === FALSE) {
- return FALSE;
- }
-
- if (count(DB::$last_result) == 0) {
- return FALSE;
- }
-
- return TRUE;
- }
-
- /**
- * @brief Comprobar si un usuario está deshabilitado
- * @param string $userLogin con el login del usuario
- * @return bool
- */
- public static function checkUserIsDisabled($userLogin) {
- $query = "SELECT user_isDisabled "
- . "FROM usrData "
- . "WHERE user_login = '" . DB::escape($userLogin) . "' LIMIT 1";
- $queryRes = DB::getResults($query, __FUNCTION__);
-
- if ($queryRes === FALSE) {
- return FALSE;
- }
-
- if ($queryRes->user_isDisabled == 0) {
- return FALSE;
- }
-
- return TRUE;
- }
-
/**
* @brief Comprobar si el grupo de LDAP está habilitado
* @param string $group con el nombre del grupo
* @return bool
*/
- private static function checkLDAPGroup($group) {
+ private static function checkLDAPGroup($group)
+ {
$ldapgroup = SP_Config::getValue('ldapgroup');
$groupName = array();
-
+
preg_match('/^cn=([\w\s-]+),.*/i', $group, $groupName);
if ($groupName[1] == $ldapgroup || $group == $ldapgroup) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
+ /**
+ * @brief Autentificación de usuarios con MySQL
+ * @param string $userLogin con el login del usuario
+ * @param string $userPass con la clave del usuario
+ * @return bool
+ *
+ * Esta función comprueba la clave del usuario. Si el usuario necesita ser migrado desde phpPMS,
+ * se ejecuta el proceso para actualizar la clave.
+ */
+ public static function authUserMySQL($userLogin, $userPass)
+ {
+ if (SP_Users::checkUserIsMigrate($userLogin)) {
+ if (!SP_Users::migrateUser($userLogin, $userPass)) {
+ return false;
+ }
+ }
+
+ $query = "SELECT user_login,"
+ . "user_pass "
+ . "FROM usrData "
+ . "WHERE user_login = '" . DB::escape($userLogin) . "' "
+ . "AND user_isMigrate = 0 "
+ . "AND user_pass = SHA1(CONCAT(user_hashSalt,'" . DB::escape($userPass) . "')) LIMIT 1";
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
+ }
+
+ if (count(DB::$last_result) == 0) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @brief Proceso para la recuperación de clave
+ * @param string $login con el login del usuario
+ * @param string $email con el email del usuario
+ * @return bool
+ */
+ public static function mailPassRecover($login, $email)
+ {
+ if (SP_Users::checkUserMail($login, $email)
+ && !SP_Users::checkUserIsDisabled($login)
+ && !SP_Users::checkUserIsLDAP($login)
+ && !SP_Users::checkPassRecoverLimit($login)
+ ) {
+ $hash = SP_Util::generate_random_bytes();
+
+ $message['action'] = _('Recuperación de Clave');
+ $message['text'][] = SP_Html::strongText(_('Se ha solicitado la recuperación de su clave de usuario.'));
+ $message['text'][] = '';
+ $message['text'][] = _('Para completar el proceso es necesario que acceda a la siguiente URL:');
+ $message['text'][] = '';
+ $message['text'][] = SP_Html::anchorText(SP_Init::$WEBURI . '/index.php?a=passreset&h=' . $hash . '&t=' . time());
+ $message['text'][] = '';
+ $message['text'][] = _('Si no ha solicitado esta acción, ignore este mensaje.');
+
+ return (SP_Common::sendEmail($message, $email, false) && SP_Users::addPassRecover($login, $hash));
+ } else {
+ return false;
+ }
+ }
}
diff --git a/inc/category.class.php b/inc/category.class.php
index e5b8c5e7..99612408 100644
--- a/inc/category.class.php
+++ b/inc/category.class.php
@@ -2,11 +2,11 @@
/**
* sysPass
- *
+ *
* @author nuxsmin
* @link http://syspass.org
- * @copyright 2014 Rubén Domínguez nuxsmin@syspass.org
- *
+ * @copyright 2012-2014 Rubén Domínguez nuxsmin@syspass.org
+ *
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
@@ -23,12 +23,14 @@
* along with sysPass. If not, see .
*
*/
+
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
/**
* Esta clase es la encargada de realizar las operaciones sobre las categorías de sysPass.
*/
-class SP_Category {
+class SP_Category
+{
public static $categoryName;
public static $categoryDescription;
public static $categoryLastId;
@@ -36,20 +38,21 @@ class SP_Category {
/**
* @brief Obtener el id de una categoría por el nombre
* @param string $categoryName con el nombre de la categoría
- * @return bool|int si la consulta es errónea devuelve bool. Si no hay registros o se obtiene el id, devuelve int
+ * @return bool|int si la consulta es errónea devuelve bool. Si no hay registros o se obtiene el id, devuelve int
*/
- public static function getCategoryIdByName($categoryName) {
+ public static function getCategoryIdByName($categoryName)
+ {
$query = "SELECT category_id "
- . "FROM categories "
- . "WHERE category_name = '" . DB::escape($categoryName) . "' LIMIT 1";
+ . "FROM categories "
+ . "WHERE category_name = '" . DB::escape($categoryName) . "' LIMIT 1";
$queryRes = DB::getResults($query, __FUNCTION__);
- if ($queryRes === FALSE) {
- return FALSE;
+ if ($queryRes === false) {
+ return false;
}
if (DB::$num_rows == 0) {
- return FALSE;
+ return false;
} else {
return $queryRes->category_id;
}
@@ -57,55 +60,56 @@ class SP_Category {
/**
* @brief Crear una nueva categoría en la BBDD
- * @param string $categoryName con el nombre de la categoría
* @return bool
*/
- public static function addCategory() {
+ public static function addCategory()
+ {
$query = "INSERT INTO categories "
- . "SET category_name = '" . DB::escape(self::$categoryName) . "',"
- . "category_description = '" . DB::escape(self::$categoryDescription) . "'";
+ . "SET category_name = '" . DB::escape(self::$categoryName) . "',"
+ . "category_description = '" . DB::escape(self::$categoryDescription) . "'";
- if (DB::doQuery($query, __FUNCTION__) === FALSE) {
- return FALSE;
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
self::$categoryLastId = DB::$lastId;
$message['action'] = _('Nueva Categoría');
- $message['text'][] = _('Nombre') . ': ' . self::$categoryName;
+ $message['text'][] = SP_Html::strongText(_('Categoría') . ': ') . self::$categoryName;
- SP_Common::wrLogInfo($message);
+ SP_Log::wrLogInfo($message);
SP_Common::sendEmail($message);
- return TRUE;
+ return true;
}
-
+
/**
* @brief Comprobar si existe una categoría duplicada
* @param int $id con el Id de la categoría a consultar
* @return bool
*/
- public static function checkDupCategory($id = NULL) {
+ public static function checkDupCategory($id = NULL)
+ {
if ($id === NULL) {
$query = "SELECT category_id "
- . "FROM categories "
- . "WHERE category_name = '" . DB::escape(self::$categoryName) . "'";
+ . "FROM categories "
+ . "WHERE category_name = '" . DB::escape(self::$categoryName) . "'";
} else {
$query = "SELECT category_id "
- . "FROM categories "
- . "WHERE category_name = '" . DB::escape(self::$categoryName) . "' AND category_id <> " . $id;
+ . "FROM categories "
+ . "WHERE category_name = '" . DB::escape(self::$categoryName) . "' AND category_id <> " . $id;
}
-
- if (DB::doQuery($query, __FUNCTION__) === FALSE) {
- return FALSE;
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
if (count(DB::$last_result) >= 1) {
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/**
@@ -113,86 +117,24 @@ class SP_Category {
* @param int $id con el id de la categoría
* @return bool
*/
- public static function delCategory($id) {
+ public static function delCategory($id)
+ {
$categoryName = self::getCategoryNameById($id);
-
- $query = "DELETE FROM categories "
- . "WHERE category_id = " . (int) $id . " LIMIT 1";
- if (DB::doQuery($query, __FUNCTION__) === FALSE) {
- return FALSE;
+ $query = "DELETE FROM categories "
+ . "WHERE category_id = " . (int)$id . " LIMIT 1";
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
$message['action'] = _('Eliminar Categoría');
- $message['text'][] = _('Nombre') . ': ' .$categoryName.' ('. $id.')';
+ $message['text'][] = SP_Html::strongText(_('Categoría') . ': ') . $categoryName . ' (' . $id . ')';
- SP_Common::wrLogInfo($message);
- SP_Common::sendEmail($message);
-
- return TRUE;
- }
-
- /**
- * @brief Actualizar una categoría en la BBDD con el id
- * @param int $id con el Id de la categoría a consultar
- * @return bool
- */
- public static function updateCategory($id) {
- $categoryName = self::getCategoryNameById($id);
-
- $query = "UPDATE categories "
- . "SET category_name = '" . DB::escape(self::$categoryName) . "',"
- . "category_description = '" . DB::escape(self::$categoryDescription) . "' "
- . "WHERE category_id = " . (int) $id . " LIMIT 1";
-
- if (DB::doQuery($query, __FUNCTION__) === FALSE) {
- return FALSE;
- }
-
- $message['action'] = _('Modificar Categoría');
- $message['text'][] = _('Nombre') . ': ' . $categoryName.' > '.self::$categoryName;
-
- SP_Common::wrLogInfo($message);
+ SP_Log::wrLogInfo($message);
SP_Common::sendEmail($message);
- return TRUE;
- }
-
- /**
- * @brief Obtiene el listado de categorías
- * @param int $id con el Id de la categoría
- * @param bool $retAssocArray para devolver un array asociativo
- * @return array con en id de categorioa como clave y en nombre como valor
- */
- public static function getCategories($id = NULL, $retAssocArray = FALSE) {
- $query = "SELECT category_id,"
- . "category_name,"
- . "category_description "
- . "FROM categories ";
-
- if (!is_null($id)) {
- $query .= "WHERE category_id = " . (int) $id . " LIMIT 1";
- } else {
- $query .= "ORDER BY category_name";
- }
-
- $queryRes = DB::getResults($query, __FUNCTION__, TRUE);
-
- if ($queryRes === FALSE) {
- return array();
- }
-
- if ($retAssocArray) {
- $resCategories = array();
-
- foreach ($queryRes as $category) {
- $resCategories[$category->category_id] = $category->category_name;
- }
-
- return $resCategories;
- }
-
- return $queryRes;
+ return true;
}
/**
@@ -200,25 +142,54 @@ class SP_Category {
* @param int $id con el Id de la categoría a consultar
* @return string con el nombre de la categoría
*/
- public static function getCategoryNameById($id) {
+ public static function getCategoryNameById($id)
+ {
$query = "SELECT category_name "
- . "FROM categories "
- . "WHERE category_id = " . (int) $id;
+ . "FROM categories "
+ . "WHERE category_id = " . (int)$id;
$queryRes = DB::getResults($query, __FUNCTION__);
- if ($queryRes === FALSE) {
- return FALSE;
+ if ($queryRes === false) {
+ return false;
}
return $queryRes->category_name;
}
+ /**
+ * @brief Actualizar una categoría en la BBDD con el id
+ * @param int $id con el Id de la categoría a consultar
+ * @return bool
+ */
+ public static function updateCategory($id)
+ {
+ $categoryName = self::getCategoryNameById($id);
+
+ $query = "UPDATE categories "
+ . "SET category_name = '" . DB::escape(self::$categoryName) . "',"
+ . "category_description = '" . DB::escape(self::$categoryDescription) . "' "
+ . "WHERE category_id = " . (int)$id . " LIMIT 1";
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
+ }
+
+ $message['action'] = _('Modificar Categoría');
+ $message['text'][] = SP_Html::strongText(_('Categoría') . ': ') . $categoryName . ' > ' . self::$categoryName;
+
+ SP_Log::wrLogInfo($message);
+ SP_Common::sendEmail($message);
+
+ return true;
+ }
+
/**
* @brief Obtener los datos de una categoría
* @param int $id con el Id de la categoría a consultar
* @return array con el nombre de la columna como clave y los datos como valor
*/
- public static function getCategoryData($id = 0) {
+ public static function getCategoryData($id = 0)
+ {
$category = array('category_id' => 0,
'category_name' => '',
'category_description' => '',
@@ -237,15 +208,54 @@ class SP_Category {
return $category;
}
-
+
+ /**
+ * @brief Obtiene el listado de categorías
+ * @param int $id con el Id de la categoría
+ * @param bool $retAssocArray para devolver un array asociativo
+ * @return array con en id de categorioa como clave y en nombre como valor
+ */
+ public static function getCategories($id = NULL, $retAssocArray = false)
+ {
+ $query = "SELECT category_id,"
+ . "category_name,"
+ . "category_description "
+ . "FROM categories ";
+
+ if (!is_null($id)) {
+ $query .= "WHERE category_id = " . (int)$id . " LIMIT 1";
+ } else {
+ $query .= "ORDER BY category_name";
+ }
+
+ $queryRes = DB::getResults($query, __FUNCTION__, true);
+
+ if ($queryRes === false) {
+ return array();
+ }
+
+ if ($retAssocArray) {
+ $resCategories = array();
+
+ foreach ($queryRes as $category) {
+ $resCategories[$category->category_id] = $category->category_name;
+ }
+
+ return $resCategories;
+ }
+
+ return $queryRes;
+ }
+
/**
* @brief Comprobar si una categoría está en uso
* @param int $id con el Id de la categoría a consultar
* @return bool
- *
+ *
* Esta función comprueba si una categoría está en uso por cuentas.
*/
- public static function checkCategoryInUse($id) {
+ public static function checkCategoryInUse($id)
+ {
$numAccounts = self::getCategoriesInAccounts($id);
@@ -259,7 +269,7 @@ class SP_Category {
return implode(' ', $out);
}
- return TRUE;
+ return true;
}
/**
@@ -267,15 +277,16 @@ class SP_Category {
* @param int $id con el Id de la categoría a consultar
* @return integer con el número total de cuentas
*/
- private static function getCategoriesInAccounts($id) {
+ private static function getCategoriesInAccounts($id)
+ {
$query = "SELECT COUNT(*) as uses "
- . "FROM accounts "
- . "WHERE account_categoryId = " . (int) $id;
+ . "FROM accounts "
+ . "WHERE account_categoryId = " . (int)$id;
$queryRes = DB::getResults($query, __FUNCTION__);
- if ($queryRes === FALSE) {
- return FALSE;
+ if ($queryRes === false) {
+ return false;
}
return $queryRes->uses;
diff --git a/inc/common.class.php b/inc/common.class.php
index 2a586ebb..ff642008 100644
--- a/inc/common.class.php
+++ b/inc/common.class.php
@@ -1,11 +1,11 @@
";
- $headers[] = "Reply-To: $replyTo";
- $headers[] = "Cc: $strFrom";
+ $mail->isHTML();
+ $newline = ' ';
- $mailbody = _('Acción') . ": " . $message['action'] . "\r\n";
- $mailbody .= _('Realizado por') . ": " . $_SESSION["ulogin"] . "\r\n";
- $mailbody .= (is_array($message['text'])) ? implode("\r\n",$message['text']) : '';
+ if ($isEvent === true) {
+ $performer = (isset($_SESSION["ulogin"])) ? $_SESSION["ulogin"] : _('N/D');
+ $body[] = SP_Html::strongText(_('Acción') . ": ") . $message['action'];
+ $body[] = SP_Html::strongText(_('Realizado por') . ": ") . $performer . ' (' . $_SERVER['REMOTE_ADDR'] . ')';
+
+ $mail->addCC(SP_Config::getValue('mailfrom'));
+ }
+
+ $body[] = (is_array($message['text'])) ? implode($newline, $message['text']) : '';
+ $body[] = '';
+ $body[] = '--';
+ $body[] = SP_Html::getAppInfo('appname') . ' - ' . SP_Html::getAppInfo('appdesc');
+ $body[] = SP_Html::anchorText(SP_Init::$WEBURI);
+
+
+ $mail->Body = implode($newline, $body);
+
+ $sendMail = $mail->send();
- $mailHeader = implode("\r\n", $headers);
-
- $log['action'] = _('Enviar Email');
-
- $sendMail = mail($mailTo, $mailSubject, $mailbody, $mailHeader);
-
// Enviar correo
- if ( $sendMail ){
- $log['text'][]= _('Correo enviado');
- } else{
+ if ($sendMail) {
+ $log['text'][] = _('Correo enviado');
+ } else {
$log['text'][] = _('Error al enviar correo');
+ $log['text'][] = 'ERROR: ' . $mail->ErrorInfo;
}
- $log['text'][] = _('Destinatario').": $mailTo";
- $log['text'][] = _('CC').": $strFrom";
+ $log['text'][] = '';
+ $log['text'][] = _('Destinatario') . ": $mailTo";
+ $log['text'][] = ($isEvent === true) ? _('CC') . ": " . SP_Config::getValue('mailfrom') : '';
- self::wrLogInfo($log);
- return $sendMail;
+ $log['action'] = _('Enviar Email');
+
+ SP_Log::wrLogInfo($log);
+ return $sendMail;
+ }
+
+ /**
+ * @brief Inicializar la clase PHPMailer
+ * @param string $mailTo con la dirección del destinatario
+ * @param string $action con la acción realizada
+ * @return object
+ */
+ public static function getEmailObject($mailTo, $action)
+ {
+ $appName = SP_Html::getAppInfo('appname');
+ $mailFrom = SP_Config::getValue('mailfrom');
+ $mailServer = SP_Config::getValue('mailserver');
+ $mailPort = SP_Config::getValue('mailport', 25);
+ $mailUser = SP_Config::getValue('mailuser');
+ $mailPass = SP_Config::getValue('mailpass');
+
+ if (!$mailServer) {
+ return false;
+ }
+
+ if (empty($mailTo)) {
+ $mailTo = $mailFrom;
+ }
+
+ $phpmailerPath = EXTENSIONS_DIR . DIRECTORY_SEPARATOR . 'phpmailer';
+ require_once $phpmailerPath . DIRECTORY_SEPARATOR . 'class.phpmailer.php';
+ require_once $phpmailerPath . DIRECTORY_SEPARATOR . 'class.smtp.php';
+
+ $mail = new PHPMailer();
+
+ $mail->isSMTP();
+ $mail->CharSet = 'utf-8';
+ $mail->SMTPAuth = true;
+ $mail->Host = $mailServer;
+ $mail->Port = $mailPort;
+ $mail->Username = $mailUser;
+ $mail->Password = $mailPass;
+ $mail->SMTPSecure = strtolower(SP_Config::getValue('mailsecurity'));
+ //$mail->SMTPDebug = 2;
+ //$mail->Debugoutput = 'error_log';
+
+ $mail->setFrom($mailFrom, $appName);
+ $mail->addAddress($mailTo);
+ $mail->addReplyTo($mailFrom, $appName);
+ $mail->WordWrap = 100;
+ $mail->Subject = $appName . ' (' . _('Aviso') . ') - ' . $action;
+
+ return $mail;
}
/**
@@ -123,9 +148,10 @@ class SP_Common {
* @param int $status devuelve el estado
* @return string documento XML
*/
- public static function printXML($description, $status = 1) {
+ public static function printXML($description, $status = 1)
+ {
if (!is_string($description)) {
- return FALSE;
+ return false;
}
$arrStrFrom = array("&", "<", ">", "\"", "\'");
@@ -135,7 +161,7 @@ class SP_Common {
$xml = "\n";
$xml .= "\n" . $status . "\n " . $cleanDescription . "\n";
-
+
header("Content-Type: application/xml");
exit($xml);
}
@@ -144,31 +170,34 @@ class SP_Common {
* @brief Devuelve una respuesta en formato JSON con el estado y el mensaje
* @param string $description mensaje a devolver
* @param int $status devuelve el estado
+ * @param string $action con la accion a realizar
* @return string respuesta JSON
*/
- public static function printJSON($description, $status = 1) {
+ public static function printJSON($description, $status = 1, $action = '')
+ {
if (!is_string($description)) {
- return FALSE;
+ return false;
}
- $arrStrFrom = array("&", "<", ">", "\"", "\'");
- $arrStrTo = array("&", "<", ">", """, "'");
+ $arrStrFrom = array("\\", '"', "'");
+ $arrStrTo = array("\\", '\"', "\'");
$cleanDescription = str_replace($arrStrFrom, $arrStrTo, $description);
- $json = array('status' => $status, 'description' => $cleanDescription);
-
+ $json = array('status' => $status, 'description' => $cleanDescription, 'action' => $action);
+
header('Content-type: application/json');
exit(json_encode($json));
}
-
+
/**
* @brief Devuelve un icono de ayuda con el mensaje
* @param int $type tipo de mensaje
* @param int $id id del mensaje
* @return string con la etiqueta html
*/
- public static function printHelpButton($type, $id) {
+ public static function printHelpButton($type, $id)
+ {
$msgHelp[0] = _('Indicar el usuario de conexión a la base de datos de phpPMS');
$msgHelp[1] = _('Indicar el nombre de la base de datos de phpPMS');
$msgHelp[2] = _('Indicar el servidor de la base de datos de phpPMS');
@@ -203,13 +232,14 @@ class SP_Common {
* @brief Devuelve un hash para verificación de formularios
* @param bool $new si es necesrio regenerar el hash
* @return string con el hash de verificación
- *
+ *
* Esta función genera un hash que permite verificar la autenticidad de un formulario
*/
- public static function getSessionKey($new = FALSE) {
+ public static function getSessionKey($new = false)
+ {
$hash = sha1(time());
- if (!isset($_SESSION["sk"]) || $new === TRUE) {
+ if (!isset($_SESSION["sk"]) || $new === true) {
$_SESSION["sk"] = $hash;
return $hash;
}
@@ -220,14 +250,15 @@ class SP_Common {
/**
* @brief Comprobar el hash de verificación de formularios
* @param string $key con el hash a comprobar
- * @return boo|string si no es correcto el hash devuelve bool. Si lo es, devuelve el hash actual.
+ * @return bool|string si no es correcto el hash devuelve bool. Si lo es, devuelve el hash actual.
*/
- public static function checkSessionKey($key) {
- if (!isset($_SESSION["sk"]) || $_SESSION["sk"] == "" || !$key){
- return FALSE;
+ public static function checkSessionKey($key)
+ {
+ if (!isset($_SESSION["sk"]) || $_SESSION["sk"] == "" || !$key) {
+ return false;
}
- return ( $_SESSION["sk"] == $key );
+ return ($_SESSION["sk"] == $key);
}
/**
@@ -237,51 +268,52 @@ class SP_Common {
* @param mixed $default opcional, valor por defecto a devolver
* @param bool $onlyCHeck opcional, comprobar si el parámetro está presente
* @param mixed $force opcional, valor devuelto si el parámeto está definido
- * @return boo|string si está presente el parámeto en la petición devuelve bool. Si lo está, devuelve el valor.
+ * @return bool|string si está presente el parámeto en la petición devuelve bool. Si lo está, devuelve el valor.
*/
- public static function parseParams($method, $param, $default = '', $onlyCHeck = FALSE, $force = FALSE){
+ public static function parseParams($method, $param, $default = '', $onlyCHeck = false, $force = false)
+ {
$out = '';
-
- switch ($method){
+
+ switch ($method) {
case 'g':
- if ( !isset($_GET[$param]) ){
+ if (!isset($_GET[$param])) {
return $default;
}
$out = $_GET[$param];
break;
case 'p':
- if ( !isset($_POST[$param]) ){
+ if (!isset($_POST[$param])) {
return $default;
}
$out = $_POST[$param];
break;
case 's':
- if ( !isset($_SESSION[$param]) ){
+ if (!isset($_SESSION[$param])) {
return $default;
}
$out = $_SESSION[$param];
break;
default :
- return FALSE;
+ return false;
}
- if ( $onlyCHeck ){
- return TRUE;
+ if ($onlyCHeck) {
+ return true;
}
-
- if ($force){
+
+ if ($force) {
return $force;
}
-
- if (is_numeric($out) && is_numeric($default)){
+
+ if (is_numeric($out) && is_numeric($default)) {
return (int)$out;
}
- if (is_string($out)){
- return ( $method != 's' ) ? SP_Html::sanitize($out) : $out;
+ if (is_string($out)) {
+ return ($method != 's') ? SP_Html::sanitize($out) : $out;
}
-
- if (is_array($out)){
+
+ if (is_array($out)) {
return $out;
}
}
diff --git a/inc/config.class.php b/inc/config.class.php
index bccea6a4..0c324c8c 100644
--- a/inc/config.class.php
+++ b/inc/config.class.php
@@ -1,27 +1,27 @@
.
-*
-*/
+/**
+ * sysPass
+ *
+ * @author nuxsmin
+ * @link http://syspass.org
+ * @copyright 2012-2014 Rubén Domínguez nuxsmin@syspass.org
+ *
+ * This file is part of sysPass.
+ *
+ * sysPass is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * sysPass 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with sysPass. If not, see .
+ *
+ */
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
@@ -40,14 +40,14 @@ defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'
* Esta clase es responsable de leer y escribir la configuración del archivo config.php
* y en la base de datos
*/
-class SP_Config{
+class SP_Config
+{
// Array asociativo clave => valor
- private static $cache = array();
- // La caché está llena??
- private static $init = false;
- // Configuracion actual en array
static $arrConfigValue;
+ private static $cache = array(); // Configuracion actual en array
+ private static $init = false; // La caché está llena??
+
/**
* @brief Obtiene un valor desde la configuración en la BBDD
* @param string $param con el parámetro de configuración
@@ -55,39 +55,41 @@ class SP_Config{
*
* Obtener el valor de un parámetro almacenado en la BBDD
*/
- public static function getConfigValue($param){
+ public static function getConfigValue($param)
+ {
$query = "SELECT config_value "
- . "FROM config "
- . "WHERE config_parameter = '$param'";
+ . "FROM config "
+ . "WHERE config_parameter = '$param'";
$queryRes = DB::getResults($query, __FUNCTION__);
- if ( $queryRes === FALSE ){
- return FALSE;
+ if ($queryRes === false) {
+ return false;
}
-
+
return $queryRes->config_value;
}
-
+
/**
* @brief Obtener array con la configuración
*
* Obtener un array con la configuración almacenada en la BBDD
*/
- public static function getConfig(){
+ public static function getConfig()
+ {
$query = "SELECT config_parameter,"
- . "config_value "
- . "FROM config";
- $queryRes = DB::getResults($query, __FUNCTION__, TRUE);
+ . "config_value "
+ . "FROM config";
+ $queryRes = DB::getResults($query, __FUNCTION__, true);
- if ( $queryRes === FALSE ){
- return FALSE;
+ if ($queryRes === false) {
+ return false;
}
-
- foreach ( $queryRes as $config ){
+
+ foreach ($queryRes as $config) {
$strKey = $config->config_parameter;
$strValue = $config->config_value;
self::$arrConfigValue[$strKey] = $strValue;
-
+
}
}
@@ -98,34 +100,35 @@ class SP_Config{
*
* Guardar la configuración en la BBDD
*/
- public static function writeConfig($mkInsert = FALSE){
+ public static function writeConfig($mkInsert = false)
+ {
foreach (self::$arrConfigValue as $key => $value) {
$key = DB::escape($key);
$value = DB::escape($value);
-
- if ( $mkInsert ){
+
+ if ($mkInsert) {
$query = "INSERT INTO config "
- . "VALUES ('$key','$value') "
- . "ON DUPLICATE KEY UPDATE config_value = '$value' ";
+ . "VALUES ('$key','$value') "
+ . "ON DUPLICATE KEY UPDATE config_value = '$value' ";
} else {
$query = "UPDATE config SET "
- . "config_value = '$value' "
- . "WHERE config_parameter = '$key'";
+ . "config_value = '$value' "
+ . "WHERE config_parameter = '$key'";
}
-
- if ( DB::doQuery($query, __FUNCTION__) === FALSE ){
- return FALSE;
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
}
-
+
$message['action'] = _('Configuración');
$message['text'][] = _('Modificar configuración');
- SP_Common::wrLogInfo($message);
+ SP_Log::wrLogInfo($message);
SP_Common::sendEmail($message);
-
- return TRUE;
- }
+
+ return true;
+ }
/**
* @brief Guardar un parámetro de configuración
@@ -133,14 +136,15 @@ class SP_Config{
* @param string $value con el calor a guardar
* @return bool
*/
- public static function setConfigValue($param, $value) {
+ public static function setConfigValue($param, $value)
+ {
$query = "INSERT INTO config "
- . "SET config_parameter = '" . DB::escape($param) . "',"
- . "config_value = '" . DB::escape($value) . "'"
- . "ON DUPLICATE KEY UPDATE config_value = '" . DB::escape($value) . "' ";
+ . "SET config_parameter = '" . DB::escape($param) . "',"
+ . "config_value = '" . DB::escape($value) . "'"
+ . "ON DUPLICATE KEY UPDATE config_value = '" . DB::escape($value) . "' ";
- if (DB::doQuery($query, __FUNCTION__) === FALSE) {
- return FALSE;
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
$message['action'] = _('Configuración');
@@ -148,10 +152,10 @@ class SP_Config{
$message['text'][] = _('Parámetro') . ': ' . $param;
$message['text'][] = _('Valor') . ': ' . $value;
- SP_Common::wrLogInfo($message);
+ SP_Log::wrLogInfo($message);
SP_Common::sendEmail($message);
- return TRUE;
+ return true;
}
/**
@@ -161,36 +165,37 @@ class SP_Config{
*
* Cargar la configuración desde la BBDD y guardarla en una variable global $CFG
*/
- public static function getDBConfig($force = FALSE){
+ public static function getDBConfig($force = false)
+ {
global $CFG;
- if ( isset ($CFG) && ! $force ){
- return TRUE;
+ if (isset ($CFG) && !$force) {
+ return true;
}
$query = "SELECT config_parameter,"
- . "config_value "
- . "FROM config";
- $queryRes = DB::getResults($query, __FUNCTION__, TRUE);
+ . "config_value "
+ . "FROM config";
+ $queryRes = DB::getResults($query, __FUNCTION__, true);
- if ( $queryRes === FALSE ){
- return FALSE;
+ if ($queryRes === false) {
+ return false;
}
-
- foreach ( $queryRes as $config ){
+
+ foreach ($queryRes as $config) {
$cfgParam = $config->config_parameter;
$cfgValue = $config->config_value;
-
- if ( strstr($cfgValue, "||") ){
- $cfgValue = explode ("||",$cfgValue);
+
+ if (strstr($cfgValue, "||")) {
+ $cfgValue = explode("||", $cfgValue);
}
$CFG["$cfgParam"] = $cfgValue;
}
-
- return TRUE;
- }
-
+
+ return true;
+ }
+
/**
* @brief Realizar backup de la BBDD y aplicación
* @return array resultado
@@ -198,82 +203,65 @@ class SP_Config{
* Realizar un backup completo de la BBDD y de la aplicación.
* Sólo es posible en entornos Linux
*/
- public static function makeBackup(){
-
- if ( SP_Util::runningOnWindows() ){
+ public static function makeBackup()
+ {
+
+ if (SP_Util::runningOnWindows()) {
$arrOut['error'] = _('Esta operación sólo es posible en entornos Linux');
return $arrOut;
}
-
+
$arrOut = array();
$error = 0;
$siteName = SP_Html::getAppInfo('appname');
$backupDir = SP_Init::$SERVERROOT;
-
- $bakDstDir = $backupDir.'/backup';
- $bakFile = $backupDir.'/backup/'.$siteName.'.tgz';
- $bakFileDB = $backupDir.'/backup/'.$siteName.'_db.sql';
- if ( ! is_dir($bakDstDir) ){
- if ( ! @mkdir($bakDstDir, 0550) ){
- $arrOut['error'] = _('No es posible crear el directorio de backups').' ('.$bakDstDir.')';
-
+ $bakDstDir = $backupDir . '/backup';
+ $bakFile = $backupDir . '/backup/' . $siteName . '.tgz';
+ $bakFileDB = $backupDir . '/backup/' . $siteName . '_db.sql';
+
+ if (!is_dir($bakDstDir)) {
+ if (!@mkdir($bakDstDir, 0550)) {
+ $arrOut['error'] = _('No es posible crear el directorio de backups') . ' (' . $bakDstDir . ')';
+
$message['action'] = _('Copia BBDD');
$message['text'][] = _('No es posible crear el directorio de backups');
- $message['text'][] = "IP: ".$_SERVER['REMOTE_ADDR'];
-
- SP_Common::wrLogInfo($message);
+
+ SP_Log::wrLogInfo($message);
$error = 1;
}
}
- if ( ! is_writable($bakDstDir) ){
+ if (!is_writable($bakDstDir)) {
$arrOut['error'] = _('Compruebe los permisos del directorio de backups');
$error = 1;
}
- if ( $error == 0 ){
+ if ($error == 0) {
$message['action'] = _('Copia BBDD');
- $message['text'][] = "IP: ".$_SERVER['REMOTE_ADDR'];
- SP_Common::wrLogInfo($message);
+ SP_Log::wrLogInfo($message);
SP_Common::sendEmail($message);
-
+
$dbhost = SP_Config::getValue("dbhost");
$dbuser = SP_Config::getValue("dbuser");
$dbpass = SP_Config::getValue("dbpass");
$dbname = SP_Config::getValue("dbname");
-
+
// Backup de la BBDD
- $command = 'mysqldump -h '.$dbhost.' -u '.$dbuser.' -p'.$dbpass.' -r "'.$bakFileDB.'" '.$dbname.' 2>&1';
+ $command = 'mysqldump -h ' . $dbhost . ' -u ' . $dbuser . ' -p' . $dbpass . ' -r "' . $bakFileDB . '" ' . $dbname . ' 2>&1';
exec($command, $resOut, $resBakDB);
-
+
// Backup de la Aplicación
- $command = 'tar czf '.$bakFile.' '.$backupDir.' --exclude "'.$bakDstDir.'" 2>&1';
+ $command = 'tar czf ' . $bakFile . ' ' . $backupDir . ' --exclude "' . $bakDstDir . '" 2>&1';
exec($command, $resOut, $resBakApp);
-
- if ( $resBakApp != 0 || $resBakDB != 0 ){
+
+ if ($resBakApp != 0 || $resBakDB != 0) {
$arrOut['error'] = implode(' ', $resOut);
}
}
-
- return $arrOut;
- }
-
- /**
- * @brief Lista todas las claves de configuración
- * @return array con nombres de claves
- *
- * Esta función devuelve todas las claves guardadas en config.php.
- */
- public static function getKeys($full = FALSE){
- self::readData();
- if ( $full ){
- return self::$cache;
- }
-
- return array_keys( self::$cache );
+ return $arrOut;
}
/**
@@ -285,75 +273,35 @@ class SP_Config{
* Esta función obtiene un valor desde config.php. Si no existe,
* $default será defuelto.
*/
- public static function getValue( $key, $default = null ) {
+ public static function getValue($key, $default = null)
+ {
self::readData();
- if( array_key_exists( $key, self::$cache )) return self::$cache[$key];
+ if (array_key_exists($key, self::$cache)) return self::$cache[$key];
return $default;
}
- /**
- * @brief Establece un valor
- * @param string $key clave
- * @param string $value valor
- * @return bool
- *
- * Esta función establece el valor y reescribe config.php. Si el archivo
- * no se puede escribir, devolverá false.
- */
- public static function setValue( $key, $value ) {
- self::readData();
-
- // Add change
- self::$cache[$key] = $value;
-
- // Write changes
- self::writeData();
- return true;
- }
-
- /**
- * @brief Elimina una clave de la configuración
- * @param string $key clave
- * @return bool
- *
- * Esta función elimina una clave de config.php. Si no tiene permiso
- * de escritura en config.php, devolverá false.
- */
- public static function deleteKey( $key ) {
- self::readData();
-
- if( array_key_exists( $key, self::$cache )) {
- // Delete key from cache
- unset( self::$cache[$key] );
-
- // Write changes
- self::writeData();
- }
-
- return true;
- }
-
/**
* @brief Carga el archivo de configuración
* @return bool
*
* Lee el archivo de configuración y lo guarda en caché
*/
- private static function readData() {
- if( self::$init ) {
+ private static function readData()
+ {
+ if (self::$init) {
return true;
}
-
- if( !file_exists( SP_Init::$SERVERROOT."/config/config.php" )){
+
+ if (!file_exists(SP_Init::$SERVERROOT . "/config/config.php")) {
return false;
}
// Include the file, save the data from $CONFIG
- include SP_Init::$SERVERROOT."/config/config.php";
-
- if( isset($CONFIG) && is_array($CONFIG) ) {
+ include SP_Init::$SERVERROOT . "/config/config.php";
+
+ if (isset($CONFIG) && is_array($CONFIG)) {
self::$cache = $CONFIG;
}
@@ -363,48 +311,96 @@ class SP_Config{
return true;
}
+ /**
+ * @brief Lista todas las claves de configuración
+ * @param bool $full obtener todas las claves y sus valores
+ * @return array con nombres de claves
+ *
+ * Esta función devuelve todas las claves guardadas en config.php.
+ */
+ public static function getKeys($full = false)
+ {
+ self::readData();
+
+ if ($full) {
+ return self::$cache;
+ }
+
+ return array_keys(self::$cache);
+ }
+
+ /**
+ * @brief Elimina una clave de la configuración
+ * @param string $key clave
+ * @return bool
+ *
+ * Esta función elimina una clave de config.php. Si no tiene permiso
+ * de escritura en config.php, devolverá false.
+ */
+ public static function deleteKey($key)
+ {
+ self::readData();
+
+ if (array_key_exists($key, self::$cache)) {
+ // Delete key from cache
+ unset(self::$cache[$key]);
+
+ // Write changes
+ self::writeData();
+ }
+
+ return true;
+ }
+
/**
* @brief Escribe en archivo de configuración
* @return bool
*/
- public static function writeData() {
- $content = " 'critical',
- 'description' => _('No es posible escribir el archivo de configuración'),
- 'hint' => 'Compruebe los permisos del directorio "config"');
+ $filename = SP_Init::$SERVERROOT . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'config.php';
- SP_Html::render('error',$errors);
+ // Write the file
+ $result = @file_put_contents($filename, $content);
+
+ if (!$result) {
+ $errors[] = array(
+ 'type' => 'critical',
+ 'description' => _('No es posible escribir el archivo de configuración'),
+ 'hint' => _('Compruebe los permisos del directorio "config"'));
+
+ SP_Html::render('error', $errors);
exit();
}
-
+
// Prevent others not to read the config
@chmod($filename, 0640);
-
- return TRUE;
+
+ return true;
}
-
+
/**
* @brief Establece los valores de configuración por defecto en config.php
* @return none
- */
- public static function setDefaultValues(){
+ */
+ public static function setDefaultValues()
+ {
self::setValue('logenabled', 1);
self::setValue('debug', 0);
self::setValue('ldapenabled', 0);
self::setValue('mailenabled', 0);
self::setValue('wikienabled', 0);
self::setValue('demoenabled', 0);
-
+
self::setValue('allowed_exts', 'PDF,JPG,GIF,PNG,ODT,ODS,DOC,DOCX,XLS,XSL,VSD,TXT,CSV,BAK');
self::setValue('allowed_size', 1024);
self::setValue('wikisearchurl', '');
@@ -420,6 +416,27 @@ class SP_Config{
self::setValue('sitelang', 'es_ES');
self::setValue('session_timeout', '300');
self::setValue('account_link', 1);
- self::setValue('account_count', 10);
+ self::setValue('account_count', 12);
+ }
+
+ /**
+ * @brief Establece un valor
+ * @param string $key clave
+ * @param string $value valor
+ * @return bool
+ *
+ * Esta función establece el valor y reescribe config.php. Si el archivo
+ * no se puede escribir, devolverá false.
+ */
+ public static function setValue($key, $value)
+ {
+ self::readData();
+
+ // Add change
+ self::$cache[$key] = $value;
+
+ // Write changes
+ self::writeData();
+ return true;
}
}
diff --git a/inc/crypt.class.php b/inc/crypt.class.php
index 985e563d..b7386f81 100644
--- a/inc/crypt.class.php
+++ b/inc/crypt.class.php
@@ -1,44 +1,167 @@
.
-*
-*/
+/**
+ * sysPass
+ *
+ * @author nuxsmin
+ * @link http://syspass.org
+ * @copyright 2012-2014 Rubén Domínguez nuxsmin@syspass.org
+ *
+ * This file is part of sysPass.
+ *
+ * sysPass is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * sysPass 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with sysPass. If not, see .
+ *
+ */
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
/**
* Esta clase es la encargada de realizar el encriptad/desencriptado de claves
*/
-class SP_Crypt {
+class SP_Crypt
+{
public $strInitialVector;
+ /**
+ * @brief Comprobar si el módulo de encriptación está disponible
+ * @return bool
+ */
+ public static function checkCryptModule()
+ {
+ $resEncDes = mcrypt_module_open('rijndael-256', '', 'cbc', '');
+
+ if ($resEncDes == false) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * @brief Generar un hash de una clave utilizando un salt
+ * @param string $pwd con la clave a 'hashear'
+ * @return string con el hash de la clave
+ */
+ public static function mkHashPassword($pwd)
+ {
+ $salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)); // Obtenemos 256 bits aleatorios en hexadecimal
+ $hash = hash("sha256", $salt . $pwd); // Añadimos el salt a la clave y rehacemos el hash
+ $hashPwd = $salt . $hash;
+ return $hashPwd;
+ }
+
+ /**
+ * @brief Comprobar el hash de una clave
+ * @param string $pwd con la clave a comprobar
+ * @param string $correctHash con el hash a comprobar
+ * @return bool
+ */
+ public static function checkHashPass($pwd, $correctHash)
+ {
+ // Obtenemos el salt de la clave
+ $salt = substr($correctHash, 0, 64);
+ // Obtenemos el hash SHA256
+ $validHash = substr($correctHash, 64, 64);
+
+ // Re-hash de la clave a comprobar
+ $testHash = hash("sha256", $salt . $pwd);
+
+ // Si los hashes son idénticos, la clave es válida
+ if ($testHash === $validHash) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @brief Crear un salt
+ * @return string con el salt creado
+ */
+ public static function makeHashSalt()
+ {
+ do {
+ $cryptIV = self::createIV();
+ $blnCheckIv = self::checkIV($cryptIV);
+ } while ($blnCheckIv == false);
+
+ return $cryptIV;
+ }
+
+ /**
+ * @brief Generar una clave encriptada
+ * @param string $pwd con la clave a encriptar
+ * @param string $masterPwd con la clave maestra
+ * @return bool
+ *
+ * Esta función llama a los métodos privados para encriptar datos.
+ */
+ public function mkEncrypt($pwd, $masterPwd = "")
+ {
+ $masterPwd = (!$masterPwd) ? $this->getSessionMasterPass() : $masterPwd;
+
+ do {
+ do {
+ $cryptIV = SP_Crypt::createIV();
+ $blnCheckIv = SP_Crypt::checkIV($cryptIV);
+ } while ($blnCheckIv == false);
+
+ $this->strInitialVector = $cryptIV;
+
+ $cryptValue = $this->encrypt($pwd, $masterPwd, $cryptIV);
+ $blnCheckEncrypted = $this->checkEncryptedPass($cryptValue);
+ } while ($blnCheckEncrypted == false);
+
+ return $cryptValue;
+ }
+
+ /**
+ * @brief Desencriptar la clave maestra de la sesión
+ * @return string con la clave maestra
+ */
+ public function getSessionMasterPass()
+ {
+ return $this->decrypt($_SESSION["mPass"], $_SESSION['mPassPwd'], $_SESSION['mPassIV']);
+ }
+
+ /**
+ * @brief Desencriptar datos con la clave maestra
+ * @param string $strEncrypted con los datos a desencriptar
+ * @param string $strPassword con la clave maestra
+ * @param string $cryptIV con el IV
+ * @return string con los datos desencriptados
+ */
+ public function decrypt($strEncrypted, $strPassword, $cryptIV)
+ {
+ $resEncDes = mcrypt_module_open('rijndael-256', '', 'cbc', '');
+ mcrypt_generic_init($resEncDes, $strPassword, $cryptIV);
+ $strDecrypted = trim(mdecrypt_generic($resEncDes, $strEncrypted));
+
+ mcrypt_generic_deinit($resEncDes);
+ mcrypt_module_close($resEncDes);
+
+ return $strDecrypted;
+ }
+
/**
* @brief Crear el vector de inicialización
* @return string con el IV
- */
- private static function createIV() {
+ */
+ private static function createIV()
+ {
$resEncDes = mcrypt_module_open('rijndael-256', '', 'cbc', '');
- if ( SP_Util::runningOnWindows() && (! defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300) ){
+ if (SP_Util::runningOnWindows() && (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300)) {
$cryptIV = mcrypt_create_iv(mcrypt_enc_get_iv_size($resEncDes), MCRYPT_RAND);
} else {
$cryptIV = mcrypt_create_iv(mcrypt_enc_get_iv_size($resEncDes), MCRYPT_DEV_URANDOM);
@@ -52,14 +175,15 @@ class SP_Crypt {
* @brief Comprobar si el vector de inicialización tiene la longitud correcta
* @param string $cryptIV con el IV
* @return bool
- */
- private static function checkIV($cryptIV){
+ */
+ private static function checkIV($cryptIV)
+ {
$strEscapeInitialVector = DB::escape($cryptIV);
- if (strlen($strEscapeInitialVector) != 32 ) {
- return FALSE;
+ if (strlen($strEscapeInitialVector) != 32) {
+ return false;
} else {
- return TRUE;
+ return true;
}
}
@@ -69,8 +193,9 @@ class SP_Crypt {
* @param string $strPassword con la clave maestra
* @param string $cryptIV con el IV
* @return string con los datos encriptados
- */
- private function encrypt($strValue, $strPassword, $cryptIV){
+ */
+ private function encrypt($strValue, $strPassword, $cryptIV)
+ {
$resEncDes = mcrypt_module_open('rijndael-256', '', 'cbc', '');
mcrypt_generic_init($resEncDes, $strPassword, $cryptIV);
$strEncrypted = mcrypt_generic($resEncDes, $strValue);
@@ -79,162 +204,47 @@ class SP_Crypt {
return $strEncrypted;
}
- /**
- * @brief Desencriptar datos con la clave maestra
- * @param string $strEncrypted con los datos a desencriptar
- * @param string $strPassword con la clave maestra
- * @param string $cryptIV con el IV
- * @return string con los datos desencriptados
- */
- public function decrypt($strEncrypted, $strPassword, $cryptIV){
- $resEncDes = mcrypt_module_open('rijndael-256', '', 'cbc', '');
- mcrypt_generic_init($resEncDes, $strPassword, $cryptIV);
- $strDecrypted = trim(mdecrypt_generic($resEncDes, $strEncrypted));
-
- mcrypt_generic_deinit($resEncDes);
- mcrypt_module_close($resEncDes);
-
- return $strDecrypted;
- }
-
- /**
- * @brief Comprobar si el módulo de encriptación está disponible
- * @param string $strEncrypted con los datos a desencriptar
- * @param string $strPassword con la clave maestra
- * @param string $cryptIV con el IV
- * @return string con los datos desencriptados
- */
- public static function checkCryptModule(){
- $resEncDes = mcrypt_module_open('rijndael-256', '', 'cbc', '');
-
- if ($resEncDes == FALSE ) {
- return FALSE;
- } else {
- return TRUE;
- }
- }
-
/**
* @brief Comprobar datos encriptados
* @param string $strEncryptedPass con los datos encriptados
* @return bool
- *
- * Esta función comprueba la longitud de los datos encriptados despues de
+ *
+ * Esta función comprueba la longitud de los datos encriptados despues de
* escaparlos con mysqli
- */
- private function checkEncryptedPass($strEncryptedPass){
+ */
+ private function checkEncryptedPass($strEncryptedPass)
+ {
$strEscapedEncryptedPass = DB::escape($strEncryptedPass);
-
- if (strlen($strEscapedEncryptedPass) != strlen($strEncryptedPass) ) {
- return FALSE;
+
+ if (strlen($strEscapedEncryptedPass) != strlen($strEncryptedPass)) {
+ return false;
} else {
- return TRUE;
+ return true;
}
}
- /**
- * @brief Generar una clave encriptada
- * @param string $pwd con la clave a encriptar
- * @param string $masterPwd con la clave maestra
- * @return bool
- *
- * Esta función llama a los métodos privados para encriptar datos.
- */
- public function mkEncrypt($pwd,$masterPwd = ""){
- $masterPwd = ( ! $masterPwd ) ? $this->getSessionMasterPass() : $masterPwd;
-
- do {
- do {
- $cryptIV = SP_Crypt::createIV();
- $blnCheckIv = SP_Crypt::checkIV($cryptIV);
- } while ($blnCheckIv == FALSE);
-
- $this->strInitialVector = $cryptIV;
-
- $cryptValue = $this->encrypt($pwd, $masterPwd, $cryptIV);
- $blnCheckEncrypted = $this->checkEncryptedPass($cryptValue);
- } while ($blnCheckEncrypted == FALSE );
-
- return $cryptValue;
- }
-
/**
* @brief Generar la clave maestra encriptada con la clave del usuario
* @param string $customPwd con la clave a encriptar
* @param string $masterPwd con la clave maestra
* @return string con la clave encriptada
- *
+ *
* Esta función llama a los métodos privados para encriptar datos.
- */
- public function mkCustomMPassEncrypt($customPwd,$masterPwd){
+ */
+ public function mkCustomMPassEncrypt($customPwd, $masterPwd)
+ {
do {
do {
$cryptIV = SP_Crypt::createIV();
$blnCheckIv = SP_Crypt::CheckIV($cryptIV);
- } while ($blnCheckIv == FALSE);
-
+ } while ($blnCheckIv == false);
+
$cryptValue = $this->encrypt($masterPwd, $customPwd, $cryptIV);
$blnCheckEncrypted = $this->checkEncryptedPass($cryptValue);
- } while ($blnCheckEncrypted == FALSE );
-
+ } while ($blnCheckEncrypted == false);
+
$dataCrypt = array($cryptValue, $cryptIV);
-
+
return $dataCrypt;
}
-
- /**
- * @brief Generar un hash de una clave utilizando un salt
- * @param string $pwd con la clave a 'hashear'
- * @return string con el hash de la clave
- */
- public static function mkHashPassword($pwd){
- $salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)); // Obtenemos 256 bits aleatorios en hexadecimal
- $hash = hash("sha256", $salt.$pwd); // Añadimos el salt a la clave y rehacemos el hash
- $hashPwd = $salt.$hash;
- return $hashPwd;
- }
-
- /**
- * @brief Comprobar el hash de una clave
- * @param string $pwd con la clave a comprobar
- * @param string $correctHash con el hash a comprobar
- * @return bool
- */
- public static function checkHashPass($pwd, $correctHash){
- // Obtenemos el salt de la clave
- $salt = substr($correctHash, 0, 64);
- // Obtenemos el hash SHA256
- $validHash = substr($correctHash, 64, 64);
-
- // Re-hash de la clave a comprobar
- $testHash = hash("sha256", $salt . $pwd);
-
- // Si los hashes son idénticos, la clave es válida
- if ( $testHash === $validHash ){
- return TRUE;
- }
-
- return FALSE;
- }
-
- /**
- * @brief Crear un salt
- * @return string con el salt creado
- */
- public static function makeHashSalt(){
- do {
- $cryptIV = self::createIV();
- $blnCheckIv = self::checkIV($cryptIV);
- } while ($blnCheckIv == FALSE);
-
- return $cryptIV;
- }
-
- /**
- * @brief Desencriptar la clave maestra de la sesión
- * @return string con la clave maestra
- */
- public function getSessionMasterPass(){
- return $this->decrypt($_SESSION["mPass"], $_SESSION['mPassPwd'], $_SESSION['mPassIV']);
- }
}
\ No newline at end of file
diff --git a/inc/customer.class.php b/inc/customer.class.php
index b31074ed..087e64d2 100644
--- a/inc/customer.class.php
+++ b/inc/customer.class.php
@@ -2,11 +2,11 @@
/**
* sysPass
- *
+ *
* @author nuxsmin
* @link http://syspass.org
- * @copyright 2014 Rubén Domínguez nuxsmin@syspass.org
- *
+ * @copyright 2012-2014 Rubén Domínguez nuxsmin@syspass.org
+ *
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
@@ -23,135 +23,54 @@
* along with sysPass. If not, see .
*
*/
+
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
/**
* Esta clase es la encargada de realizar las operaciones sobre los clientes de sysPass
*/
-class SP_Customer {
+class SP_Customer
+{
public static $customerName;
public static $customerDescription;
public static $customerLastId;
public static $customerHash;
- /**
- * @brief Obtener el listado de clientes
- * @param int $customerId con el Id del cliente
- * @param bool $retAssocArray para devolver un array asociativo
- * @return array con el id de cliente como clave y el nombre como valor
- */
- public static function getCustomers($customerId = NULL, $retAssocArray = FALSE) {
- $query = "SELECT customer_id,"
- . "customer_name, "
- . "customer_description "
- . "FROM customers ";
-
- if (!is_null($customerId)) {
- $query .= "WHERE customer_id = " . (int) $customerId . " LIMIT 1";
- } else {
- $query .= "ORDER BY customer_name";
- }
-
- $queryRes = DB::getResults($query, __FUNCTION__, TRUE);
-
- if ($queryRes === FALSE) {
- return array();
- }
-
- if ($retAssocArray) {
- $resCustomers = array();
-
- foreach ($queryRes as $customer) {
- $resCustomers[$customer->customer_id] = $customer->customer_name;
- }
-
- return $resCustomers;
- }
-
- return $queryRes;
- }
-
/**
* @brief Crear un nuevo cliente en la BBDD
* @return bool
*/
- public static function addCustomer() {
+ public static function addCustomer()
+ {
$query = "INSERT INTO customers "
- . "SET customer_name = '" . DB::escape(self::$customerName) . "',"
- . "customer_hash = '" . self::mkCustomerHash() . "'";
+ . "SET customer_name = '" . DB::escape(self::$customerName) . "',"
+ . "customer_hash = '" . self::mkCustomerHash() . "'";
- if (DB::doQuery($query, __FUNCTION__) === FALSE) {
- return FALSE;
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
self::$customerLastId = DB::$lastId;
$message['action'] = _('Nuevo Cliente');
- $message['text'][] = _('Nombre') . ': ' . self::$customerName;
+ $message['text'][] = SP_Html::strongText(_('Cliente') . ': ') . self::$customerName;
- SP_Common::wrLogInfo($message);
+ SP_Log::wrLogInfo($message);
SP_Common::sendEmail($message);
- return TRUE;
- }
-
- /**
- * @brief Actualizar un cliente en la BBDD
- * @return bool
- */
- public static function updateCustomer($id) {
- $query = "UPDATE customers "
- . "SET customer_name = '" . DB::escape(self::$customerName) . "',"
- . "customer_description = '" . DB::escape(self::$customerDescription) . "',"
- . "customer_hash = '" . self::mkCustomerHash() . "' "
- . "WHERE customer_id = " . (int) $id;
-
- if (DB::doQuery($query, __FUNCTION__) === FALSE) {
- return FALSE;
- }
-
- $message['action'] = _('Actualizar Cliente');
- $message['text'][] = _('Nombre') . ': ' . self::$customerName;
-
- SP_Common::wrLogInfo($message);
- SP_Common::sendEmail($message);
-
- return TRUE;
- }
-
- /**
- * @brief Eliminar un cliente de la BBDD
- * @param int $id con el Id del cliente a eliminar
- * @return bool
- */
- public static function delCustomer($id) {
- $customerName = self::getCustomerById($id);
-
- $query = "DELETE FROM customers "
- . "WHERE customer_id = " . (int) $id . " LIMIT 1";
-
- if (DB::doQuery($query, __FUNCTION__) === FALSE) {
- return FALSE;
- }
-
- $message['action'] = _('Eliminar Cliente');
- $message['text'][] = _('Nombre') . ': ' . $customerName;
-
- SP_Common::wrLogInfo($message);
- SP_Common::sendEmail($message);
-
- return TRUE;
+ return true;
}
/**
* @brief Crear un hash con el nombre del cliente
* @return string con el hash generado
- *
+ *
* Esta función crear un hash para detectar clientes duplicados mediante
* la eliminación de carácteres especiales y capitalización
*/
- private static function mkCustomerHash() {
+ private static function mkCustomerHash()
+ {
$charsSrc = array(
".", " ", "_", ", ", "-", ";
", "'", "\"", ":", "(", ")", "|", "/");
@@ -162,46 +81,56 @@ class SP_Customer {
}
/**
- * @brief Comprobar si existe un cliente duplicado comprobando el hash
+ * @brief Actualizar un cliente en la BBDD
+ * @param int $id con el Id del cliente
* @return bool
*/
- public static function checkDupCustomer($id = NULL) {
- if ($id === NULL) {
- $query = "SELECT customer_id "
- . "FROM customers "
- . "WHERE customer_hash = '" . self::mkCustomerHash() . "'";
- } else {
- $query = "SELECT customer_id "
- . "FROM customers "
- . "WHERE customer_hash = '" . self::mkCustomerHash() . "' AND customer_id <> " . $id;
- }
-
- if (DB::doQuery($query, __FUNCTION__) === FALSE) {
- return FALSE;
+ public static function updateCustomer($id)
+ {
+ $customerName = self::getCustomerById($id);
+
+ $query = "UPDATE customers "
+ . "SET customer_name = '" . DB::escape(self::$customerName) . "',"
+ . "customer_description = '" . DB::escape(self::$customerDescription) . "',"
+ . "customer_hash = '" . self::mkCustomerHash() . "' "
+ . "WHERE customer_id = " . (int)$id;
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
- if (count(DB::$last_result) >= 1) {
- return FALSE;
- }
+ $message['action'] = _('Actualizar Cliente');
+ $message['text'][] = SP_Html::strongText(_('Cliente') . ': ') . $customerName . ' > ' . self::$customerName;
- return TRUE;
+ SP_Log::wrLogInfo($message);
+ SP_Common::sendEmail($message);
+
+ return true;
}
/**
- * @brief Obtener el Id de un cliente por su nombre
- * @return int con el Id del cliente
+ * @brief Eliminar un cliente de la BBDD
+ * @param int $id con el Id del cliente a eliminar
+ * @return bool
*/
- public static function getCustomerByName() {
- $query = "SELECT customer_id "
- . "FROM customers "
- . "WHERE customer_hash = '" . self::mkCustomerHash() . "' LIMIT 1";
- $queryRes = DB::getResults($query, __FUNCTION__);
+ public static function delCustomer($id)
+ {
+ $customerName = self::getCustomerById($id);
- if ($queryRes === FALSE) {
- return FALSE;
+ $query = "DELETE FROM customers "
+ . "WHERE customer_id = " . (int)$id . " LIMIT 1";
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
}
- return $queryRes->customer_id;
+ $message['action'] = _('Eliminar Cliente');
+ $message['text'][] = SP_Html::strongText(_('Cliente') . ': ') . $customerName;
+
+ SP_Log::wrLogInfo($message);
+ SP_Common::sendEmail($message);
+
+ return true;
}
/**
@@ -209,25 +138,73 @@ class SP_Customer {
* @param int $id con el Id del cliente
* @return string con el nombre del cliente
*/
- public static function getCustomerById($id) {
+ public static function getCustomerById($id)
+ {
$query = "SELECT customer_name "
- . "FROM customers "
- . "WHERE customer_id = " . (int) $id . " LIMIT 1";
+ . "FROM customers "
+ . "WHERE customer_id = " . (int)$id . " LIMIT 1";
$queryRes = DB::getResults($query, __FUNCTION__);
- if ($queryRes === FALSE) {
- return FALSE;
+ if ($queryRes === false) {
+ return false;
}
return $queryRes->customer_name;
}
+ /**
+ * @brief Comprobar si existe un cliente duplicado comprobando el hash
+ * @param int $id opcional con el Id del cliente
+ * @return bool
+ */
+ public static function checkDupCustomer($id = NULL)
+ {
+ if ($id === NULL) {
+ $query = "SELECT customer_id "
+ . "FROM customers "
+ . "WHERE customer_hash = '" . self::mkCustomerHash() . "'";
+ } else {
+ $query = "SELECT customer_id "
+ . "FROM customers "
+ . "WHERE customer_hash = '" . self::mkCustomerHash() . "' AND customer_id <> " . $id;
+ }
+
+ if (DB::doQuery($query, __FUNCTION__) === false) {
+ return false;
+ }
+
+ if (count(DB::$last_result) >= 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @brief Obtener el Id de un cliente por su nombre
+ * @return int con el Id del cliente
+ */
+ public static function getCustomerByName()
+ {
+ $query = "SELECT customer_id "
+ . "FROM customers "
+ . "WHERE customer_hash = '" . self::mkCustomerHash() . "' LIMIT 1";
+ $queryRes = DB::getResults($query, __FUNCTION__);
+
+ if ($queryRes === false) {
+ return false;
+ }
+
+ return $queryRes->customer_id;
+ }
+
/**
* @brief Obtener los datos de un cliente
* @param int $id con el Id del cliente a consultar
* @return array con el nombre de la columna como clave y los datos como valor
*/
- public static function getCustomerData($id = 0) {
+ public static function getCustomerData($id = 0)
+ {
$customer = array('customer_id' => 0,
'customer_name' => '',
'customer_description' => '',
@@ -247,14 +224,53 @@ class SP_Customer {
return $customer;
}
+ /**
+ * @brief Obtener el listado de clientes
+ * @param int $customerId con el Id del cliente
+ * @param bool $retAssocArray para devolver un array asociativo
+ * @return array con el id de cliente como clave y el nombre como valor
+ */
+ public static function getCustomers($customerId = NULL, $retAssocArray = false)
+ {
+ $query = "SELECT customer_id,"
+ . "customer_name, "
+ . "customer_description "
+ . "FROM customers ";
+
+ if (!is_null($customerId)) {
+ $query .= "WHERE customer_id = " . (int)$customerId . " LIMIT 1";
+ } else {
+ $query .= "ORDER BY customer_name";
+ }
+
+ $queryRes = DB::getResults($query, __FUNCTION__, true);
+
+ if ($queryRes === false) {
+ return array();
+ }
+
+ if ($retAssocArray) {
+ $resCustomers = array();
+
+ foreach ($queryRes as $customer) {
+ $resCustomers[$customer->customer_id] = $customer->customer_name;
+ }
+
+ return $resCustomers;
+ }
+
+ return $queryRes;
+ }
+
/**
* @brief Comprobar si un cliente está en uso
* @param int $id con el Id del cliente a consultar
* @return bool
- *
+ *
* Esta función comprueba si un cliente está en uso por cuentas.
*/
- public static function checkCustomerInUse($id) {
+ public static function checkCustomerInUse($id)
+ {
$count['accounts'] = self::getCustomerInAccounts($id);
return $count;
}
@@ -264,15 +280,16 @@ class SP_Customer {
* @param int $id con el Id del cliente a consultar
* @return integer con el número total de cuentas
*/
- private static function getCustomerInAccounts($id) {
+ private static function getCustomerInAccounts($id)
+ {
$query = "SELECT COUNT(*) as uses "
- . "FROM accounts "
- . "WHERE account_customerId = " . (int) $id;
+ . "FROM accounts "
+ . "WHERE account_customerId = " . (int)$id;
$queryRes = DB::getResults($query, __FUNCTION__);
- if ($queryRes === FALSE) {
- return FALSE;
+ if ($queryRes === false) {
+ return false;
}
return $queryRes->uses;
diff --git a/inc/db.class.php b/inc/db.class.php
index 4b85bdbf..37265cb2 100644
--- a/inc/db.class.php
+++ b/inc/db.class.php
@@ -2,11 +2,11 @@
/**
* sysPass
- *
+ *
* @author nuxsmin
* @link http://syspass.org
- * @copyright 2012 Rubén Domínguez nuxsmin@syspass.org
- *
+ * @copyright 2012-2014 Rubén Domínguez nuxsmin@syspass.org
+ *
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
@@ -23,33 +23,59 @@
* along with sysPass. If not, see .
*
*/
+
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
/**
* Esta clase es la encargada de realizar las operaciones con la BBDD de sysPass.
*/
-class DB {
-
- private static $_db;
+class DB
+{
static $last_result;
static $affected_rows;
static $lastId;
static $txtError;
static $numError;
static $num_rows;
+ private static $_db;
- function __construct() {
-
+ /**
+ * @brief Comprobar que la base de datos existe
+ * @return bool
+ */
+ public static function checkDatabaseExist()
+ {
+ if (!self::connection()) {
+ return false;
+ }
+
+ $query = 'SELECT COUNT(*) '
+ . 'FROM information_schema.tables'
+ . " WHERE table_schema='" . SP_Config::getValue("dbname") . "' "
+ . "AND table_name = 'usrData';";
+
+ $resquery = self::$_db->query($query);
+
+ if ($resquery) {
+ $row = $resquery->fetch_row();
+ }
+
+ if (!$resquery || $row[0] == 0) {
+ return false;
+ }
+
+ return true;
}
/**
* @brief Realizar la conexión con la BBDD
* @return bool
- *
+ *
* Esta función utiliza mysqli para conectar con la base de datos.
* Guarda el objeto creado en la variable $_db de la clase
*/
- private static function connection() {
+ private static function connection()
+ {
if (self::$_db) {
return true;
}
@@ -76,18 +102,65 @@ class DB {
}
/**
- * @brief Escapar una cadena de texto
- * @param string $str con la cadena a escapar
- * @return string con la cadena escapada
- *
- * Esta función utiliza mysqli para escapar cadenas de texto.
+ * @brief Obtener los datos para generar un select
+ * @param string $tblName con el nombre de la tabla a cunsultar
+ * @param string $tblColId con el nombre de la columna del tipo Id a mostrar
+ * @param string $tblColName con el nombre de la columna del tipo Name a mostrar
+ * @param array $arrFilter con las columnas a filtrar
+ * @param array $arrOrder con el orden de las columnas
+ * @return array con los valores del select con el Id como clave y el nombre como valor
*/
- public static function escape($str) {
- if (self::connection()) {
- return self::$_db->real_escape_string(trim($str));
- } else {
- return $str;
+ public static function getValuesForSelect($tblName, $tblColId, $tblColName, $arrFilter = NULL, $arrOrder = NULL)
+ {
+ if (!$tblName || !$tblColId || !$tblColName) {
+ return;
}
+
+ $strFilter = (is_array($arrFilter)) ? " WHERE " . implode(" OR ", $arrFilter) : "";
+ $strOrder = (is_array($arrOrder)) ? " ORDER BY " . implode(",", $arrOrder) : 'ORDER BY ' . $tblColName . ' ASC';
+
+ $query = "SELECT $tblColId, $tblColName FROM $tblName $strFilter $strOrder";
+ $queryRes = self::getResults($query, __FUNCTION__, true);
+
+ if ($queryRes === false) {
+ return false;
+ }
+
+ $arrValues = array();
+
+ foreach ($queryRes as $row) {
+ $arrValues[$row->$tblColId] = $row->$tblColName;
+ }
+
+ return $arrValues;
+ }
+
+ /**
+ * @brief Obtener los resultados de una consulta
+ * @param string $query con la consulta a realizar
+ * @param string $querySource con el nombre de la función que realiza la consulta
+ * @param bool $retArray devolver un array si la consulta tiene esultados
+ * @return bool|array devuelve bool si hay un error. Devuelve array con el array de registros devueltos
+ */
+ public static function getResults($query, $querySource, $retArray = false)
+ {
+ if ($query) {
+ self::doQuery($query, $querySource);
+ }
+
+ if (self::$numError || self::$num_rows === 0) {
+ return false;
+ }
+
+ if (is_null(self::$numError) && count(self::$last_result) === 0) {
+ return true;
+ }
+
+ if ($retArray === true && is_object(self::$last_result)) {
+ return array(self::$last_result);
+ }
+
+ return self::$last_result;
}
/**
@@ -96,7 +169,8 @@ class DB {
* @param string $querySource con el nombre de la función que realiza la consulta
* @return bool|int devuleve bool si hay un error. Devuelve int con el número de registros
*/
- public static function doQuery($query, $querySource) {
+ public static function doQuery($query, $querySource)
+ {
if (!self::connection()) {
return false;
}
@@ -116,8 +190,8 @@ class DB {
$message['text'][] = self::$_db->error . '(' . self::$_db->errno . ')';
$message['text'][] = "SQL: " . self::escape($query);
- SP_Common::wrLogInfo($message);
- return FALSE;
+ SP_Log::wrLogInfo($message);
+ return false;
}
if ($isSelect) {
@@ -144,88 +218,18 @@ class DB {
}
/**
- * @brief Obtener los resultados de una consulta
- * @param string $query con la consulta a realizar
- * @param string $querySource con el nombre de la función que realiza la consulta
- * @return bool|array devuelve bool si hay un error. Devuelve array con el array de registros devueltos
+ * @brief Escapar una cadena de texto
+ * @param string $str con la cadena a escapar
+ * @return string con la cadena escapada
+ *
+ * Esta función utiliza mysqli para escapar cadenas de texto.
*/
- public static function getResults($query, $querySource, $retArray = FALSE) {
- if ($query) {
- self::doQuery($query, $querySource);
+ public static function escape($str)
+ {
+ if (self::connection()) {
+ return self::$_db->real_escape_string(trim($str));
+ } else {
+ return $str;
}
-
- if (self::$numError || self::$num_rows === 0) {
- return FALSE;
- }
-
- if (is_null(self::$numError) && count(self::$last_result) === 0) {
- return TRUE;
- }
-
- if ($retArray === TRUE && is_object(self::$last_result)) {
- return array(self::$last_result);
- }
-
- return self::$last_result;
}
-
- /**
- * @brief Comprobar que la base de datos existe
- * @return bool
- */
- public static function checkDatabaseExist() {
- if (!self::connection()) {
- return false;
- }
-
- $query = 'SELECT COUNT(*) '
- . 'FROM information_schema.tables'
- . " WHERE table_schema='" . SP_Config::getValue("dbname") . "' "
- . "AND table_name = 'usrData';";
-
- $resquery = self::$_db->query($query);
-
- if ($resquery) {
- $row = $resquery->fetch_row();
- }
-
- if (!$resquery || $row[0] == 0) {
- return false;
- }
-
- return true;
- }
-
- /**
- * @brief Obtener los datos para generar un select
- * @param string $tblName con el nombre de la tabla a cunsultar
- * @param string $tblColId con el nombre de la columna a mostrar
- * @param array $arrFilter con las columnas a filtrar
- * @param array $arrOrder con el orden de las columnas
- * @return array con los valores del select con el Id como clave y el nombre como valor
- */
- public static function getValuesForSelect($tblName, $tblColId, $tblColName, $arrFilter = '', $arrOrder = '') {
- if (!$tblName || !$tblColId || !$tblColName) {
- return;
- }
-
- $strFilter = ( is_array($arrFilter) ) ? " WHERE " . implode(" OR ", $arrFilter) : "";
- $strOrder = ( is_array($arrOrder) ) ? " ORDER BY " . implode(",", $arrOrder) : 'ORDER BY ' . $tblColName . ' ASC';
-
- $query = "SELECT $tblColId, $tblColName FROM $tblName $strFilter $strOrder";
- $queryRes = self::getResults($query, __FUNCTION__, TRUE);
-
- if ($queryRes === FALSE) {
- return FALSE;
- }
-
- $arrValues = array();
-
- foreach ($queryRes as $row) {
- $arrValues[$row->$tblColId] = $row->$tblColName;
- }
-
- return $arrValues;
- }
-
}
diff --git a/inc/dbstructure.sql b/inc/dbstructure.sql
index 08ddfb29..6b255a5f 100644
--- a/inc/dbstructure.sql
+++ b/inc/dbstructure.sql
@@ -26,7 +26,7 @@ CREATE TABLE `accFiles` (
`accfile_extension` varchar(10) NOT NULL,
PRIMARY KEY (`accfile_id`),
KEY `IDX_accountId` (`accfile_accountId`)
-) ENGINE=MyISAM AUTO_INCREMENT=62 DEFAULT CHARSET=utf8;
+) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -42,7 +42,7 @@ CREATE TABLE `accGroups` (
`accgroup_groupId` int(10) unsigned NOT NULL,
PRIMARY KEY (`accgroup_id`),
KEY `IDX_accountId` (`accgroup_accountId`)
-) ENGINE=MyISAM AUTO_INCREMENT=69 DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;
+) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -77,7 +77,7 @@ CREATE TABLE `accHistory` (
`accHistory_otherGroupEdit` varchar(45) DEFAULT NULL,
PRIMARY KEY (`acchistory_id`),
KEY `IDX_accountId` (`acchistory_accountId`)
-) ENGINE=MyISAM AUTO_INCREMENT=285 DEFAULT CHARSET=utf8;
+) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -93,7 +93,7 @@ CREATE TABLE `accUsers` (
`accuser_userId` int(10) unsigned NOT NULL,
PRIMARY KEY (`accuser_id`),
KEY `idx_account` (`accuser_accountId`)
-) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -127,7 +127,7 @@ CREATE TABLE `accounts` (
KEY `IDX_userId` (`account_userGroupId`,`account_userId`),
KEY `IDX_customerId` (`account_customerId`),
FULLTEXT KEY `IDX_searchTxt` (`account_name`,`account_login`,`account_url`,`account_notes`)
-) ENGINE=MyISAM AUTO_INCREMENT=44 DEFAULT CHARSET=utf8;
+) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -142,7 +142,7 @@ CREATE TABLE `categories` (
`category_name` varchar(50) NOT NULL,
`category_description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`category_id`)
-) ENGINE=MyISAM AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
+) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -173,7 +173,7 @@ CREATE TABLE `customers` (
`customer_description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`customer_id`),
KEY `IDX_name` (`customer_name`,`customer_hash`)
-) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
+) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -188,10 +188,11 @@ CREATE TABLE `log` (
`log_date` int(10) unsigned NOT NULL,
`log_login` varchar(25) NOT NULL,
`log_userId` tinyint(3) unsigned NOT NULL,
+ `log_ipAddress` varchar(45) NOT NULL,
`log_action` varchar(50) NOT NULL,
`log_description` text NOT NULL,
PRIMARY KEY (`log_id`)
-) ENGINE=MyISAM AUTO_INCREMENT=640 DEFAULT CHARSET=utf8;
+) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -206,11 +207,11 @@ CREATE TABLE `usrData` (
`user_name` varchar(80) NOT NULL,
`user_groupId` tinyint(3) unsigned NOT NULL,
`user_secGroupId` tinyint(3) unsigned DEFAULT NULL,
- `user_login` varchar(30) NOT NULL,
+ `user_login` varchar(50) NOT NULL,
`user_pass` varbinary(40) NOT NULL,
`user_mPass` varbinary(32) NOT NULL,
`user_mIV` varbinary(32) NOT NULL,
- `user_email` varchar(50) DEFAULT NULL,
+ `user_email` varchar(80) DEFAULT NULL,
`user_notes` text,
`user_count` int(10) unsigned NOT NULL DEFAULT '0',
`user_profileId` tinyint(4) NOT NULL,
@@ -223,10 +224,11 @@ CREATE TABLE `usrData` (
`user_isDisabled` bit(1) NOT NULL DEFAULT b'0',
`user_hashSalt` varbinary(40) NOT NULL,
`user_isMigrate` bit(1) DEFAULT b'0',
+ `user_isChangePass` bit(1) DEFAULT b'0',
PRIMARY KEY (`user_id`),
UNIQUE KEY `IDX_login` (`user_login`),
KEY `IDX_pass` (`user_pass`)
-) ENGINE=MyISAM AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
+) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -241,7 +243,25 @@ CREATE TABLE `usrGroups` (
`usergroup_name` varchar(50) NOT NULL,
`usergroup_description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`usergroup_id`)
-) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
+) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Table structure for table `usrPassRecover`
+--
+
+DROP TABLE IF EXISTS `usrPassRecover`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `usrPassRecover` (
+ `userpassr_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ `userpassr_userId` smallint(5) unsigned NOT NULL,
+ `userpassr_hash` varbinary(40) NOT NULL,
+ `userpassr_date` int(10) unsigned NOT NULL,
+ `userpassr_used` bit(1) NOT NULL,
+ PRIMARY KEY (`userpassr_id`),
+ KEY `IDX_userId` (`userpassr_userId`,`userpassr_date`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -275,7 +295,7 @@ CREATE TABLE `usrProfiles` (
`userProfile_pAppMgmtCategories` bit(1) DEFAULT b'0',
`userProfile_pAppMgmtCustomers` bit(1) DEFAULT b'0',
PRIMARY KEY (`userprofile_id`)
-) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
+) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
diff --git a/inc/ext/phpmailer/LICENSE b/inc/ext/phpmailer/LICENSE
new file mode 100644
index 00000000..8e0763d1
--- /dev/null
+++ b/inc/ext/phpmailer/LICENSE
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ 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
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ , 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/inc/ext/phpmailer/class.phpmailer.php b/inc/ext/phpmailer/class.phpmailer.php
new file mode 100644
index 00000000..b29fd06f
--- /dev/null
+++ b/inc/ext/phpmailer/class.phpmailer.php
@@ -0,0 +1,3363 @@
+
+ * @author Jim Jagielski (jimjag)
+ * @author Andy Prevost (codeworxtech)
+ * @author Brent R. Matzelle (original founder)
+ * @copyright 2013 Marcus Bointon
+ * @copyright 2010 - 2012 Jim Jagielski
+ * @copyright 2004 - 2009 Andy Prevost
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
+ * @note This program is distributed in the hope that it will be useful - WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+if (version_compare(PHP_VERSION, '5.0.0', '<')) {
+ exit("Sorry, PHPMailer will only run on PHP version 5 or greater!\n");
+}
+
+/**
+ * PHPMailer - PHP email creation and transport class.
+ * PHP Version 5.0.0
+ * @package PHPMailer
+ * @author Marcus Bointon (coolbru)
+ * @author Jim Jagielski (jimjag)
+ * @author Andy Prevost (codeworxtech)
+ * @author Brent R. Matzelle (original founder)
+ * @copyright 2013 Marcus Bointon
+ * @copyright 2010 - 2012 Jim Jagielski
+ * @copyright 2004 - 2009 Andy Prevost
+ */
+class PHPMailer
+{
+ /**
+ * The PHPMailer Version number.
+ * @type string
+ */
+ public $Version = '5.2.7';
+
+ /**
+ * Email priority.
+ * Options: 1 = High, 3 = Normal, 5 = low.
+ * @type int
+ */
+ public $Priority = 3;
+
+ /**
+ * The character set of the message.
+ * @type string
+ */
+ public $CharSet = 'iso-8859-1';
+
+ /**
+ * The MIME Content-type of the message.
+ * @type string
+ */
+ public $ContentType = 'text/plain';
+
+ /**
+ * The message encoding.
+ * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
+ * @type string
+ */
+ public $Encoding = '8bit';
+
+ /**
+ * Holds the most recent mailer error message.
+ * @type string
+ */
+ public $ErrorInfo = '';
+
+ /**
+ * The From email address for the message.
+ * @type string
+ */
+ public $From = 'root@localhost';
+
+ /**
+ * The From name of the message.
+ * @type string
+ */
+ public $FromName = 'Root User';
+
+ /**
+ * The Sender email (Return-Path) of the message.
+ * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
+ * @type string
+ */
+ public $Sender = '';
+
+ /**
+ * The Return-Path of the message.
+ * If empty, it will be set to either From or Sender.
+ * @type string
+ */
+ public $ReturnPath = '';
+
+ /**
+ * The Subject of the message.
+ * @type string
+ */
+ public $Subject = '';
+
+ /**
+ * An HTML or plain text message body.
+ * If HTML then call isHTML(true).
+ * @type string
+ */
+ public $Body = '';
+
+ /**
+ * The plain-text message body.
+ * This body can be read by mail clients that do not have HTML email
+ * capability such as mutt & Eudora.
+ * Clients that can read HTML will view the normal Body.
+ * @type string
+ */
+ public $AltBody = '';
+
+ /**
+ * An iCal message part body.
+ * Only supported in simple alt or alt_inline message types
+ * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
+ * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
+ * @link http://kigkonsult.se/iCalcreator/
+ * @type string
+ */
+ public $Ical = '';
+
+ /**
+ * The complete compiled MIME message body.
+ * @access protected
+ * @type string
+ */
+ protected $MIMEBody = '';
+
+ /**
+ * The complete compiled MIME message headers.
+ * @type string
+ * @access protected
+ */
+ protected $MIMEHeader = '';
+
+ /**
+ * Extra headers that createHeader() doesn't fold in.
+ * @type string
+ * @access protected
+ */
+ protected $mailHeader = '';
+
+ /**
+ * Word-wrap the message body to this number of chars.
+ * @type int
+ */
+ public $WordWrap = 0;
+
+ /**
+ * Which method to use to send mail.
+ * Options: "mail", "sendmail", or "smtp".
+ * @type string
+ */
+ public $Mailer = 'mail';
+
+ /**
+ * The path to the sendmail program.
+ * @type string
+ */
+ public $Sendmail = '/usr/sbin/sendmail';
+
+ /**
+ * Whether mail() uses a fully sendmail-compatible MTA.
+ * One which supports sendmail's "-oi -f" options.
+ * @type bool
+ */
+ public $UseSendmailOptions = true;
+
+ /**
+ * Path to PHPMailer plugins.
+ * Useful if the SMTP class is not in the PHP include path.
+ * @type string
+ * @deprecated Should not be needed now there is an autoloader.
+ */
+ public $PluginDir = '';
+
+ /**
+ * The email address that a reading confirmation should be sent to.
+ * @type string
+ */
+ public $ConfirmReadingTo = '';
+
+ /**
+ * The hostname to use in Message-Id and Received headers
+ * and as default HELO string.
+ * If empty, the value returned
+ * by SERVER_NAME is used or 'localhost.localdomain'.
+ * @type string
+ */
+ public $Hostname = '';
+
+ /**
+ * An ID to be used in the Message-Id header.
+ * If empty, a unique id will be generated.
+ * @type string
+ */
+ public $MessageID = '';
+
+ /**
+ * The message Date to be used in the Date header.
+ * If empty, the current date will be added.
+ * @type string
+ */
+ public $MessageDate = '';
+
+ /**
+ * SMTP hosts.
+ * Either a single hostname or multiple semicolon-delimited hostnames.
+ * You can also specify a different port
+ * for each host by using this format: [hostname:port]
+ * (e.g. "smtp1.example.com:25;smtp2.example.com").
+ * Hosts will be tried in order.
+ * @type string
+ */
+ public $Host = 'localhost';
+
+ /**
+ * The default SMTP server port.
+ * @type int
+ * @Todo Why is this needed when the SMTP class takes care of it?
+ */
+ public $Port = 25;
+
+ /**
+ * The SMTP HELO of the message.
+ * Default is $Hostname.
+ * @type string
+ * @see PHPMailer::$Hostname
+ */
+ public $Helo = '';
+
+ /**
+ * The secure connection prefix.
+ * Options: "", "ssl" or "tls"
+ * @type string
+ */
+ public $SMTPSecure = '';
+
+ /**
+ * Whether to use SMTP authentication.
+ * Uses the Username and Password properties.
+ * @type bool
+ * @see PHPMailer::$Username
+ * @see PHPMailer::$Password
+ */
+ public $SMTPAuth = false;
+
+ /**
+ * SMTP username.
+ * @type string
+ */
+ public $Username = '';
+
+ /**
+ * SMTP password.
+ * @type string
+ */
+ public $Password = '';
+
+ /**
+ * SMTP auth type.
+ * Options are LOGIN (default), PLAIN, NTLM, CRAM-MD5
+ * @type string
+ */
+ public $AuthType = '';
+
+ /**
+ * SMTP realm.
+ * Used for NTLM auth
+ * @type string
+ */
+ public $Realm = '';
+
+ /**
+ * SMTP workstation.
+ * Used for NTLM auth
+ * @type string
+ */
+ public $Workstation = '';
+
+ /**
+ * The SMTP server timeout in seconds.
+ * @type int
+ */
+ public $Timeout = 10;
+
+ /**
+ * SMTP class debug output mode.
+ * Options: 0 = off, 1 = commands, 2 = commands and data
+ * @type int
+ * @see SMTP::$do_debug
+ */
+ public $SMTPDebug = 0;
+
+ /**
+ * The function/method to use for debugging output.
+ * Options: "echo" or "error_log"
+ * @type string
+ * @see SMTP::$Debugoutput
+ */
+ public $Debugoutput = "echo";
+
+ /**
+ * Whether to keep SMTP connection open after each message.
+ * If this is set to true then to close the connection
+ * requires an explicit call to smtpClose().
+ * @type bool
+ */
+ public $SMTPKeepAlive = false;
+
+ /**
+ * Whether to split multiple to addresses into multiple messages
+ * or send them all in one message.
+ * @type bool
+ */
+ public $SingleTo = false;
+
+ /**
+ * Storage for addresses when SingleTo is enabled.
+ * @type array
+ * @todo This should really not be public
+ */
+ public $SingleToArray = array();
+
+ /**
+ * Whether to generate VERP addresses on send.
+ * Only applicable when sending via SMTP.
+ * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
+ * @type bool
+ */
+ public $do_verp = false;
+
+ /**
+ * Whether to allow sending messages with an empty body.
+ * @type bool
+ */
+ public $AllowEmpty = false;
+
+ /**
+ * The default line ending.
+ * @note The default remains "\n". We force CRLF where we know
+ * it must be used via self::CRLF.
+ * @type string
+ */
+ public $LE = "\n";
+
+ /**
+ * DKIM selector.
+ * @type string
+ */
+ public $DKIM_selector = '';
+
+ /**
+ * DKIM Identity.
+ * Usually the email address used as the source of the email
+ * @type string
+ */
+ public $DKIM_identity = '';
+
+ /**
+ * DKIM passphrase.
+ * Used if your key is encrypted.
+ * @type string
+ */
+ public $DKIM_passphrase = '';
+
+ /**
+ * DKIM signing domain name.
+ * @example 'example.com'
+ * @type string
+ */
+ public $DKIM_domain = '';
+
+ /**
+ * DKIM private key file path.
+ * @type string
+ */
+ public $DKIM_private = '';
+
+ /**
+ * Callback Action function name.
+ *
+ * The function that handles the result of the send email action.
+ * It is called out by send() for each email sent.
+ *
+ * Value can be any php callable: http://www.php.net/is_callable
+ *
+ * Parameters:
+ * bool $result result of the send action
+ * string $to email address of the recipient
+ * string $cc cc email addresses
+ * string $bcc bcc email addresses
+ * string $subject the subject
+ * string $body the email body
+ * string $from email address of sender
+ * @type string
+ */
+ public $action_function = '';
+
+ /**
+ * What to use in the X-Mailer header.
+ * Options: null for default, whitespace for none, or a string to use
+ * @type string
+ */
+ public $XMailer = '';
+
+ /**
+ * An instance of the SMTP sender class.
+ * @type SMTP
+ * @access protected
+ */
+ protected $smtp = null;
+
+ /**
+ * The array of 'to' addresses.
+ * @type array
+ * @access protected
+ */
+ protected $to = array();
+
+ /**
+ * The array of 'cc' addresses.
+ * @type array
+ * @access protected
+ */
+ protected $cc = array();
+
+ /**
+ * The array of 'bcc' addresses.
+ * @type array
+ * @access protected
+ */
+ protected $bcc = array();
+
+ /**
+ * The array of reply-to names and addresses.
+ * @type array
+ * @access protected
+ */
+ protected $ReplyTo = array();
+
+ /**
+ * An array of all kinds of addresses.
+ * Includes all of $to, $cc, $bcc, $replyto
+ * @type array
+ * @access protected
+ */
+ protected $all_recipients = array();
+
+ /**
+ * The array of attachments.
+ * @type array
+ * @access protected
+ */
+ protected $attachment = array();
+
+ /**
+ * The array of custom headers.
+ * @type array
+ * @access protected
+ */
+ protected $CustomHeader = array();
+
+ /**
+ * The most recent Message-ID (including angular brackets).
+ * @type string
+ * @access protected
+ */
+ protected $lastMessageID = '';
+
+ /**
+ * The message's MIME type.
+ * @type string
+ * @access protected
+ */
+ protected $message_type = '';
+
+ /**
+ * The array of MIME boundary strings.
+ * @type array
+ * @access protected
+ */
+ protected $boundary = array();
+
+ /**
+ * The array of available languages.
+ * @type array
+ * @access protected
+ */
+ protected $language = array();
+
+ /**
+ * The number of errors encountered.
+ * @type integer
+ * @access protected
+ */
+ protected $error_count = 0;
+
+ /**
+ * The S/MIME certificate file path.
+ * @type string
+ * @access protected
+ */
+ protected $sign_cert_file = '';
+
+ /**
+ * The S/MIME key file path.
+ * @type string
+ * @access protected
+ */
+ protected $sign_key_file = '';
+
+ /**
+ * The S/MIME password for the key.
+ * Used only if the key is encrypted.
+ * @type string
+ * @access protected
+ */
+ protected $sign_key_pass = '';
+
+ /**
+ * Whether to throw exceptions for errors.
+ * @type bool
+ * @access protected
+ */
+ protected $exceptions = false;
+
+ /**
+ * Error severity: message only, continue processing
+ */
+ const STOP_MESSAGE = 0;
+
+ /**
+ * Error severity: message, likely ok to continue processing
+ */
+ const STOP_CONTINUE = 1;
+
+ /**
+ * Error severity: message, plus full stop, critical error reached
+ */
+ const STOP_CRITICAL = 2;
+
+ /**
+ * SMTP RFC standard line ending
+ */
+ const CRLF = "\r\n";
+
+ /**
+ * Constructor
+ * @param bool $exceptions Should we throw external exceptions?
+ */
+ public function __construct($exceptions = false)
+ {
+ $this->exceptions = ($exceptions == true);
+ //Make sure our autoloader is loaded
+// if (version_compare(PHP_VERSION, '5.1.2', '>=')) {
+// $al = spl_autoload_functions();
+// if ($al === false or !in_array('PHPMailerAutoload', $al)) {
+// require 'PHPMailerAutoload.php';
+// }
+// }
+ }
+
+ /**
+ * Destructor.
+ */
+ public function __destruct()
+ {
+ if ($this->Mailer == 'smtp') { //close any open SMTP connection nicely
+ $this->smtpClose();
+ }
+ }
+
+ /**
+ * Call mail() in a safe_mode-aware fashion.
+ * Also, unless sendmail_path points to sendmail (or something that
+ * claims to be sendmail), don't pass params (not a perfect fix,
+ * but it will do)
+ * @param string $to To
+ * @param string $subject Subject
+ * @param string $body Message Body
+ * @param string $header Additional Header(s)
+ * @param string $params Params
+ * @access private
+ * @return bool
+ */
+ private function mailPassthru($to, $subject, $body, $header, $params)
+ {
+ //Check overloading of mail function to avoid double-encoding
+ if (ini_get('mbstring.func_overload') & 1) {
+ $subject = $this->secureHeader($subject);
+ } else {
+ $subject = $this->encodeHeader($this->secureHeader($subject));
+ }
+ if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
+ $rt = @mail($to, $subject, $body, $header);
+ } else {
+ $rt = @mail($to, $subject, $body, $header, $params);
+ }
+ return $rt;
+ }
+
+ /**
+ * Output debugging info via user-defined method.
+ * Only if debug output is enabled.
+ * @see PHPMailer::$Debugoutput
+ * @see PHPMailer::$SMTPDebug
+ * @param string $str
+ */
+ protected function edebug($str)
+ {
+ if (!$this->SMTPDebug) {
+ return;
+ }
+ switch ($this->Debugoutput) {
+ case 'error_log':
+ error_log($str);
+ break;
+ case 'html':
+ //Cleans up output a bit for a better looking display that's HTML-safe
+ echo htmlentities(preg_replace('/[\r\n]+/', '', $str), ENT_QUOTES, $this->CharSet) . " \n";
+ break;
+ case 'echo':
+ default:
+ echo $str."\n";
+ }
+ }
+
+ /**
+ * Sets message type to HTML or plain.
+ * @param bool $ishtml True for HTML mode.
+ * @return void
+ */
+ public function isHTML($ishtml = true)
+ {
+ if ($ishtml) {
+ $this->ContentType = 'text/html';
+ } else {
+ $this->ContentType = 'text/plain';
+ }
+ }
+
+ /**
+ * Send messages using SMTP.
+ * @return void
+ */
+ public function isSMTP()
+ {
+ $this->Mailer = 'smtp';
+ }
+
+ /**
+ * Send messages using PHP's mail() function.
+ * @return void
+ */
+ public function isMail()
+ {
+ $this->Mailer = 'mail';
+ }
+
+ /**
+ * Send messages using $Sendmail.
+ * @return void
+ */
+ public function isSendmail()
+ {
+ if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
+ $this->Sendmail = '/usr/sbin/sendmail';
+ }
+ $this->Mailer = 'sendmail';
+ }
+
+ /**
+ * Send messages using qmail.
+ * @return void
+ */
+ public function isQmail()
+ {
+ if (!stristr(ini_get('sendmail_path'), 'qmail')) {
+ $this->Sendmail = '/var/qmail/bin/qmail-inject';
+ }
+ $this->Mailer = 'qmail';
+ }
+
+ /**
+ * Add a "To" address.
+ * @param string $address
+ * @param string $name
+ * @return bool true on success, false if address already used
+ */
+ public function addAddress($address, $name = '')
+ {
+ return $this->addAnAddress('to', $address, $name);
+ }
+
+ /**
+ * Add a "CC" address.
+ * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
+ * @param string $address
+ * @param string $name
+ * @return bool true on success, false if address already used
+ */
+ public function addCC($address, $name = '')
+ {
+ return $this->addAnAddress('cc', $address, $name);
+ }
+
+ /**
+ * Add a "BCC" address.
+ * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
+ * @param string $address
+ * @param string $name
+ * @return bool true on success, false if address already used
+ */
+ public function addBCC($address, $name = '')
+ {
+ return $this->addAnAddress('bcc', $address, $name);
+ }
+
+ /**
+ * Add a "Reply-to" address.
+ * @param string $address
+ * @param string $name
+ * @return bool
+ */
+ public function addReplyTo($address, $name = '')
+ {
+ return $this->addAnAddress('Reply-To', $address, $name);
+ }
+
+ /**
+ * Add an address to one of the recipient arrays.
+ * Addresses that have been added already return false, but do not throw exceptions
+ * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
+ * @param string $address The email address to send to
+ * @param string $name
+ * @throws phpmailerException
+ * @return bool true on success, false if address already used or invalid in some way
+ * @access protected
+ */
+ protected function addAnAddress($kind, $address, $name = '')
+ {
+ if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
+ $this->setError($this->lang('Invalid recipient array') . ': ' . $kind);
+ $this->edebug($this->lang('Invalid recipient array') . ': ' . $kind);
+ if ($this->exceptions) {
+ throw new phpmailerException('Invalid recipient array: ' . $kind);
+ }
+ return false;
+ }
+ $address = trim($address);
+ $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
+ if (!$this->validateAddress($address)) {
+ $this->setError($this->lang('invalid_address') . ': ' . $address);
+ $this->edebug($this->lang('invalid_address') . ': ' . $address);
+ if ($this->exceptions) {
+ throw new phpmailerException($this->lang('invalid_address') . ': ' . $address);
+ }
+ return false;
+ }
+ if ($kind != 'Reply-To') {
+ if (!isset($this->all_recipients[strtolower($address)])) {
+ array_push($this->$kind, array($address, $name));
+ $this->all_recipients[strtolower($address)] = true;
+ return true;
+ }
+ } else {
+ if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
+ $this->ReplyTo[strtolower($address)] = array($address, $name);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Set the From and FromName properties.
+ * @param string $address
+ * @param string $name
+ * @param bool $auto Whether to also set the Sender address, defaults to true
+ * @throws phpmailerException
+ * @return bool
+ */
+ public function setFrom($address, $name = '', $auto = true)
+ {
+ $address = trim($address);
+ $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
+ if (!$this->validateAddress($address)) {
+ $this->setError($this->lang('invalid_address') . ': ' . $address);
+ $this->edebug($this->lang('invalid_address') . ': ' . $address);
+ if ($this->exceptions) {
+ throw new phpmailerException($this->lang('invalid_address') . ': ' . $address);
+ }
+ return false;
+ }
+ $this->From = $address;
+ $this->FromName = $name;
+ if ($auto) {
+ if (empty($this->Sender)) {
+ $this->Sender = $address;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return the Message-ID header of the last email.
+ * Technically this is the value from the last time the headers were created,
+ * but it's also the message ID of the last sent message except in
+ * pathological cases.
+ * @return string
+ */
+ public function getLastMessageID()
+ {
+ return $this->lastMessageID;
+ }
+
+ /**
+ * Check that a string looks like an email address.
+ * @param string $address The email address to check
+ * @param string $patternselect A selector for the validation pattern to use :
+ * 'auto' - pick best one automatically;
+ * 'pcre8' - use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
+ * 'pcre' - use old PCRE implementation;
+ * 'php' - use PHP built-in FILTER_VALIDATE_EMAIL; faster, less thorough;
+ * 'noregex' - super fast, really dumb.
+ * @return bool
+ * @static
+ * @access public
+ */
+ public static function validateAddress($address, $patternselect = 'auto')
+ {
+ if ($patternselect == 'auto') {
+ if (defined(
+ 'PCRE_VERSION'
+ )
+ ) { //Check this instead of extension_loaded so it works when that function is disabled
+ if (version_compare(PCRE_VERSION, '8.0') >= 0) {
+ $patternselect = 'pcre8';
+ } else {
+ $patternselect = 'pcre';
+ }
+ } else {
+ //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
+ if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
+ $patternselect = 'php';
+ } else {
+ $patternselect = 'noregex';
+ }
+ }
+ }
+ switch ($patternselect) {
+ case 'pcre8':
+ /**
+ * Conforms to RFC5322: Uses *correct* regex on which FILTER_VALIDATE_EMAIL is
+ * based; So why not use FILTER_VALIDATE_EMAIL? Because it was broken to
+ * not allow a@b type valid addresses :(
+ * @link http://squiloople.com/2009/12/20/email-address-validation/
+ * @copyright 2009-2010 Michael Rushton
+ * Feel free to use and redistribute this code. But please keep this copyright notice.
+ */
+ return (bool)preg_match(
+ '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
+ '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
+ '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
+ '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
+ '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
+ '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
+ '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
+ '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
+ '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
+ $address
+ );
+ break;
+ case 'pcre':
+ //An older regex that doesn't need a recent PCRE
+ return (bool)preg_match(
+ '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
+ '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
+ '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
+ '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
+ '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
+ '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
+ '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
+ '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
+ '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
+ '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
+ $address
+ );
+ break;
+ case 'php':
+ default:
+ return (bool)filter_var($address, FILTER_VALIDATE_EMAIL);
+ break;
+ case 'noregex':
+ //No PCRE! Do something _very_ approximate!
+ //Check the address is 3 chars or longer and contains an @ that's not the first or last char
+ return (strlen($address) >= 3
+ and strpos($address, '@') >= 1
+ and strpos($address, '@') != strlen($address) - 1);
+ break;
+ }
+ }
+
+ /**
+ * Create a message and send it.
+ * Uses the sending method specified by $Mailer.
+ * @throws phpmailerException
+ * @return bool false on error - See the ErrorInfo property for details of the error.
+ */
+ public function send()
+ {
+ try {
+ if (!$this->preSend()) {
+ return false;
+ }
+ return $this->postSend();
+ } catch (phpmailerException $e) {
+ $this->mailHeader = '';
+ $this->setError($e->getMessage());
+ if ($this->exceptions) {
+ throw $e;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Prepare a message for sending.
+ * @throws phpmailerException
+ * @return bool
+ */
+ public function preSend()
+ {
+ try {
+ $this->mailHeader = "";
+ if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
+ throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
+ }
+
+ // Set whether the message is multipart/alternative
+ if (!empty($this->AltBody)) {
+ $this->ContentType = 'multipart/alternative';
+ }
+
+ $this->error_count = 0; // reset errors
+ $this->setMessageType();
+ // Refuse to send an empty message unless we are specifically allowing it
+ if (!$this->AllowEmpty and empty($this->Body)) {
+ throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
+ }
+
+ $this->MIMEHeader = $this->createHeader();
+ $this->MIMEBody = $this->createBody();
+
+ // To capture the complete message when using mail(), create
+ // an extra header list which createHeader() doesn't fold in
+ if ($this->Mailer == 'mail') {
+ if (count($this->to) > 0) {
+ $this->mailHeader .= $this->addrAppend("To", $this->to);
+ } else {
+ $this->mailHeader .= $this->headerLine("To", "undisclosed-recipients:;");
+ }
+ $this->mailHeader .= $this->headerLine(
+ 'Subject',
+ $this->encodeHeader($this->secureHeader(trim($this->Subject)))
+ );
+ }
+
+ // Sign with DKIM if enabled
+ if (!empty($this->DKIM_domain)
+ && !empty($this->DKIM_private)
+ && !empty($this->DKIM_selector)
+ && !empty($this->DKIM_domain)
+ && file_exists($this->DKIM_private)) {
+ $header_dkim = $this->DKIM_Add(
+ $this->MIMEHeader . $this->mailHeader,
+ $this->encodeHeader($this->secureHeader($this->Subject)),
+ $this->MIMEBody
+ );
+ $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
+ str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
+ }
+ return true;
+
+ } catch (phpmailerException $e) {
+ $this->setError($e->getMessage());
+ if ($this->exceptions) {
+ throw $e;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Actually send a message.
+ * Send the email via the selected mechanism
+ * @throws phpmailerException
+ * @return bool
+ */
+ public function postSend()
+ {
+ try {
+ // Choose the mailer and send through it
+ switch ($this->Mailer) {
+ case 'sendmail':
+ case 'qmail':
+ return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
+ case 'smtp':
+ return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
+ case 'mail':
+ return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
+ default:
+ if (method_exists($this, $this->Mailer.'Send')) {
+ $sendMethod = $this->Mailer.'Send';
+ return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
+ } else {
+ return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
+ }
+ }
+ } catch (phpmailerException $e) {
+ $this->setError($e->getMessage());
+ $this->edebug($e->getMessage());
+ if ($this->exceptions) {
+ throw $e;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Send mail using the $Sendmail program.
+ * @param string $header The message headers
+ * @param string $body The message body
+ * @see PHPMailer::$Sendmail
+ * @throws phpmailerException
+ * @access protected
+ * @return bool
+ */
+ protected function sendmailSend($header, $body)
+ {
+ if ($this->Sender != '') {
+ if ($this->Mailer == 'qmail') {
+ $sendmail = sprintf("%s -f%s", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
+ } else {
+ $sendmail = sprintf("%s -oi -f%s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
+ }
+ } else {
+ if ($this->Mailer == 'qmail') {
+ $sendmail = sprintf("%s", escapeshellcmd($this->Sendmail));
+ } else {
+ $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
+ }
+ }
+ if ($this->SingleTo === true) {
+ foreach ($this->SingleToArray as $val) {
+ if (!@$mail = popen($sendmail, 'w')) {
+ throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ fputs($mail, "To: " . $val . "\n");
+ fputs($mail, $header);
+ fputs($mail, $body);
+ $result = pclose($mail);
+ // implement call back function if it exists
+ $isSent = ($result == 0) ? 1 : 0;
+ $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
+ if ($result != 0) {
+ throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ }
+ } else {
+ if (!@$mail = popen($sendmail, 'w')) {
+ throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ fputs($mail, $header);
+ fputs($mail, $body);
+ $result = pclose($mail);
+ // implement call back function if it exists
+ $isSent = ($result == 0) ? 1 : 0;
+ $this->doCallback($isSent, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
+ if ($result != 0) {
+ throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Send mail using the PHP mail() function.
+ * @param string $header The message headers
+ * @param string $body The message body
+ * @link http://www.php.net/manual/en/book.mail.php
+ * @throws phpmailerException
+ * @access protected
+ * @return bool
+ */
+ protected function mailSend($header, $body)
+ {
+ $toArr = array();
+ foreach ($this->to as $t) {
+ $toArr[] = $this->addrFormat($t);
+ }
+ $to = implode(', ', $toArr);
+
+ if (empty($this->Sender)) {
+ $params = " ";
+ } else {
+ $params = sprintf("-f%s", $this->Sender);
+ }
+ if ($this->Sender != '' and !ini_get('safe_mode')) {
+ $old_from = ini_get('sendmail_from');
+ ini_set('sendmail_from', $this->Sender);
+ }
+ $rt = false;
+ if ($this->SingleTo === true && count($toArr) > 1) {
+ foreach ($toArr as $val) {
+ $rt = $this->mailPassthru($val, $this->Subject, $body, $header, $params);
+ // implement call back function if it exists
+ $isSent = ($rt == 1) ? 1 : 0;
+ $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
+ }
+ } else {
+ $rt = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
+ // implement call back function if it exists
+ $isSent = ($rt == 1) ? 1 : 0;
+ $this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
+ }
+ if (isset($old_from)) {
+ ini_set('sendmail_from', $old_from);
+ }
+ if (!$rt) {
+ throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
+ }
+ return true;
+ }
+
+ /**
+ * Get an instance to use for SMTP operations.
+ * Override this function to load your own SMTP implementation
+ * @return SMTP
+ */
+ public function getSMTPInstance()
+ {
+ if (!is_object($this->smtp)) {
+ $this->smtp = new SMTP;
+ }
+ return $this->smtp;
+ }
+
+ /**
+ * Send mail via SMTP.
+ * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
+ * Uses the PHPMailerSMTP class by default.
+ * @see PHPMailer::getSMTPInstance() to use a different class.
+ * @param string $header The message headers
+ * @param string $body The message body
+ * @throws phpmailerException
+ * @uses SMTP
+ * @access protected
+ * @return bool
+ */
+ protected function smtpSend($header, $body)
+ {
+ $bad_rcpt = array();
+
+ if (!$this->smtpConnect()) {
+ throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
+ }
+ $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
+ if (!$this->smtp->mail($smtp_from)) {
+ $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
+ throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
+ }
+
+ // Attempt to send to all recipients
+ foreach ($this->to as $to) {
+ if (!$this->smtp->recipient($to[0])) {
+ $bad_rcpt[] = $to[0];
+ $isSent = 0;
+ } else {
+ $isSent = 1;
+ }
+ $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body, $this->From);
+ }
+ foreach ($this->cc as $cc) {
+ if (!$this->smtp->recipient($cc[0])) {
+ $bad_rcpt[] = $cc[0];
+ $isSent = 0;
+ } else {
+ $isSent = 1;
+ }
+ $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body, $this->From);
+ }
+ foreach ($this->bcc as $bcc) {
+ if (!$this->smtp->recipient($bcc[0])) {
+ $bad_rcpt[] = $bcc[0];
+ $isSent = 0;
+ } else {
+ $isSent = 1;
+ }
+ $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body, $this->From);
+ }
+
+ //Only send the DATA command if we have viable recipients
+ if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
+ throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
+ }
+ if ($this->SMTPKeepAlive == true) {
+ $this->smtp->reset();
+ } else {
+ $this->smtp->quit();
+ $this->smtp->close();
+ }
+ if (count($bad_rcpt) > 0) { //Create error message for any bad addresses
+ throw new phpmailerException(
+ $this->lang('recipients_failed') . implode(', ', $bad_rcpt),
+ self::STOP_CONTINUE
+ );
+ }
+ return true;
+ }
+
+ /**
+ * Initiate a connection to an SMTP server.
+ * Returns false if the operation failed.
+ * @param array $options An array of options compatible with stream_context_create()
+ * @uses SMTP
+ * @access public
+ * @throws phpmailerException
+ * @return bool
+ */
+ public function smtpConnect($options = array())
+ {
+ if (is_null($this->smtp)) {
+ $this->smtp = $this->getSMTPInstance();
+ }
+
+ //Already connected?
+ if ($this->smtp->connected()) {
+ return true;
+ }
+
+ $this->smtp->setTimeout($this->Timeout);
+ $this->smtp->setDebugLevel($this->SMTPDebug);
+ $this->smtp->setDebugOutput($this->Debugoutput);
+ $this->smtp->setVerp($this->do_verp);
+ $hosts = explode(';', $this->Host);
+ $lastexception = null;
+
+ foreach ($hosts as $hostentry) {
+ $hostinfo = array();
+ if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
+ //Not a valid host entry
+ continue;
+ }
+ //$hostinfo[2]: optional ssl or tls prefix
+ //$hostinfo[3]: the hostname
+ //$hostinfo[4]: optional port number
+ //The host string prefix can temporarily override the current setting for SMTPSecure
+ //If it's not specified, the default value is used
+ $prefix = '';
+ $tls = ($this->SMTPSecure == 'tls');
+ if ($hostinfo[2] == 'ssl' or ($hostinfo[2] == '' and $this->SMTPSecure == 'ssl')) {
+ $prefix = 'ssl://';
+ $tls = false; //Can't have SSL and TLS at once
+ } elseif ($hostinfo[2] == 'tls') {
+ $tls = true;
+ //tls doesn't use a prefix
+ }
+ $host = $hostinfo[3];
+ $port = $this->Port;
+ $tport = (integer)$hostinfo[4];
+ if ($tport > 0 and $tport < 65536) {
+ $port = $tport;
+ }
+ if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
+ try {
+ if ($this->Helo) {
+ $hello = $this->Helo;
+ } else {
+ $hello = $this->serverHostname();
+ }
+ $this->smtp->hello($hello);
+
+ if ($tls) {
+ if (!$this->smtp->startTLS()) {
+ throw new phpmailerException($this->lang('connect_host'));
+ }
+ //We must resend HELO after tls negotiation
+ $this->smtp->hello($hello);
+ }
+ if ($this->SMTPAuth) {
+ if (!$this->smtp->authenticate(
+ $this->Username,
+ $this->Password,
+ $this->AuthType,
+ $this->Realm,
+ $this->Workstation
+ )
+ ) {
+ throw new phpmailerException($this->lang('authenticate'));
+ }
+ }
+ return true;
+ } catch (phpmailerException $e) {
+ $lastexception = $e;
+ //We must have connected, but then failed TLS or Auth, so close connection nicely
+ $this->smtp->quit();
+ }
+ }
+ }
+ //If we get here, all connection attempts have failed, so close connection hard
+ $this->smtp->close();
+ //As we've caught all exceptions, just report whatever the last one was
+ if ($this->exceptions and !is_null($lastexception)) {
+ throw $lastexception;
+ }
+ return false;
+ }
+
+ /**
+ * Close the active SMTP session if one exists.
+ * @return void
+ */
+ public function smtpClose()
+ {
+ if ($this->smtp !== null) {
+ if ($this->smtp->connected()) {
+ $this->smtp->quit();
+ $this->smtp->close();
+ }
+ }
+ }
+
+ /**
+ * Set the language for error messages.
+ * Returns false if it cannot load the language file.
+ * The default language is English.
+ * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
+ * @param string $lang_path Path to the language file directory, with trailing separator (slash)
+ * @return bool
+ * @access public
+ */
+ public function setLanguage($langcode = 'en', $lang_path = 'language/')
+ {
+ //Define full set of translatable strings
+ $PHPMAILER_LANG = array(
+ 'authenticate' => 'SMTP Error: Could not authenticate.',
+ 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
+ 'data_not_accepted' => 'SMTP Error: data not accepted.',
+ 'empty_message' => 'Message body empty',
+ 'encoding' => 'Unknown encoding: ',
+ 'execute' => 'Could not execute: ',
+ 'file_access' => 'Could not access file: ',
+ 'file_open' => 'File Error: Could not open file: ',
+ 'from_failed' => 'The following From address failed: ',
+ 'instantiate' => 'Could not instantiate mail function.',
+ 'invalid_address' => 'Invalid address',
+ 'mailer_not_supported' => ' mailer is not supported.',
+ 'provide_address' => 'You must provide at least one recipient email address.',
+ 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
+ 'signing' => 'Signing Error: ',
+ 'smtp_connect_failed' => 'SMTP connect() failed.',
+ 'smtp_error' => 'SMTP server error: ',
+ 'variable_set' => 'Cannot set or reset variable: '
+ );
+ //Overwrite language-specific strings.
+ //This way we'll never have missing translations - no more "language string failed to load"!
+ $l = true;
+ $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
+ if ($langcode != 'en') { //There is no English translation file
+ //Make sure language file path is readable
+ if (!is_readable($lang_file)) {
+ $l = false;
+ } else {
+ $l = include $lang_file;
+ }
+ }
+ $this->language = $PHPMAILER_LANG;
+ return ($l == true); //Returns false if language not found
+ }
+
+ /**
+ * Get the array of strings for the current language.
+ * @return array
+ */
+ public function getTranslations()
+ {
+ return $this->language;
+ }
+
+ /**
+ * Create recipient headers.
+ * @access public
+ * @param string $type
+ * @param array $addr An array of recipient,
+ * where each recipient is a 2-element indexed array with element 0 containing an address
+ * and element 1 containing a name, like:
+ * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
+ * @return string
+ */
+ public function addrAppend($type, $addr)
+ {
+ $addresses = array();
+ foreach ($addr as $a) {
+ $addresses[] = $this->addrFormat($a);
+ }
+ return $type . ': ' . implode(', ', $addresses) . $this->LE;
+ }
+
+ /**
+ * Format an address for use in a message header.
+ * @access public
+ * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
+ * like array('joe@example.com', 'Joe User')
+ * @return string
+ */
+ public function addrFormat($addr)
+ {
+ if (empty($addr[1])) { // No name provided
+ return $this->secureHeader($addr[0]);
+ } else {
+ return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . " <" . $this->secureHeader(
+ $addr[0]
+ ) . ">";
+ }
+ }
+
+ /**
+ * Word-wrap message.
+ * For use with mailers that do not automatically perform wrapping
+ * and for quoted-printable encoded messages.
+ * Original written by philippe.
+ * @param string $message The message to wrap
+ * @param integer $length The line length to wrap to
+ * @param bool $qp_mode Whether to run in Quoted-Printable mode
+ * @access public
+ * @return string
+ */
+ public function wrapText($message, $length, $qp_mode = false)
+ {
+ $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
+ // If utf-8 encoding is used, we will need to make sure we don't
+ // split multibyte characters when we wrap
+ $is_utf8 = (strtolower($this->CharSet) == "utf-8");
+ $lelen = strlen($this->LE);
+ $crlflen = strlen(self::CRLF);
+
+ $message = $this->fixEOL($message);
+ if (substr($message, -$lelen) == $this->LE) {
+ $message = substr($message, 0, -$lelen);
+ }
+
+ $line = explode($this->LE, $message); // Magic. We know fixEOL uses $LE
+ $message = '';
+ for ($i = 0; $i < count($line); $i++) {
+ $line_part = explode(' ', $line[$i]);
+ $buf = '';
+ for ($e = 0; $e < count($line_part); $e++) {
+ $word = $line_part[$e];
+ if ($qp_mode and (strlen($word) > $length)) {
+ $space_left = $length - strlen($buf) - $crlflen;
+ if ($e != 0) {
+ if ($space_left > 20) {
+ $len = $space_left;
+ if ($is_utf8) {
+ $len = $this->utf8CharBoundary($word, $len);
+ } elseif (substr($word, $len - 1, 1) == "=") {
+ $len--;
+ } elseif (substr($word, $len - 2, 1) == "=") {
+ $len -= 2;
+ }
+ $part = substr($word, 0, $len);
+ $word = substr($word, $len);
+ $buf .= ' ' . $part;
+ $message .= $buf . sprintf("=%s", self::CRLF);
+ } else {
+ $message .= $buf . $soft_break;
+ }
+ $buf = '';
+ }
+ while (strlen($word) > 0) {
+ if ($length <= 0) {
+ break;
+ }
+ $len = $length;
+ if ($is_utf8) {
+ $len = $this->utf8CharBoundary($word, $len);
+ } elseif (substr($word, $len - 1, 1) == "=") {
+ $len--;
+ } elseif (substr($word, $len - 2, 1) == "=") {
+ $len -= 2;
+ }
+ $part = substr($word, 0, $len);
+ $word = substr($word, $len);
+
+ if (strlen($word) > 0) {
+ $message .= $part . sprintf("=%s", self::CRLF);
+ } else {
+ $buf = $part;
+ }
+ }
+ } else {
+ $buf_o = $buf;
+ $buf .= ($e == 0) ? $word : (' ' . $word);
+
+ if (strlen($buf) > $length and $buf_o != '') {
+ $message .= $buf_o . $soft_break;
+ $buf = $word;
+ }
+ }
+ }
+ $message .= $buf . self::CRLF;
+ }
+
+ return $message;
+ }
+
+ /**
+ * Find the last character boundary prior to $maxLength in a utf-8
+ * quoted (printable) encoded string.
+ * Original written by Colin Brown.
+ * @access public
+ * @param string $encodedText utf-8 QP text
+ * @param int $maxLength find last character boundary prior to this length
+ * @return int
+ */
+ public function utf8CharBoundary($encodedText, $maxLength)
+ {
+ $foundSplitPos = false;
+ $lookBack = 3;
+ while (!$foundSplitPos) {
+ $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
+ $encodedCharPos = strpos($lastChunk, "=");
+ if ($encodedCharPos !== false) {
+ // Found start of encoded character byte within $lookBack block.
+ // Check the encoded byte value (the 2 chars after the '=')
+ $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
+ $dec = hexdec($hex);
+ if ($dec < 128) { // Single byte character.
+ // If the encoded char was found at pos 0, it will fit
+ // otherwise reduce maxLength to start of the encoded char
+ $maxLength = ($encodedCharPos == 0) ? $maxLength :
+ $maxLength - ($lookBack - $encodedCharPos);
+ $foundSplitPos = true;
+ } elseif ($dec >= 192) { // First byte of a multi byte character
+ // Reduce maxLength to split at start of character
+ $maxLength = $maxLength - ($lookBack - $encodedCharPos);
+ $foundSplitPos = true;
+ } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
+ $lookBack += 3;
+ }
+ } else {
+ // No encoded character found
+ $foundSplitPos = true;
+ }
+ }
+ return $maxLength;
+ }
+
+
+ /**
+ * Set the body wrapping.
+ * @access public
+ * @return void
+ */
+ public function setWordWrap()
+ {
+ if ($this->WordWrap < 1) {
+ return;
+ }
+
+ switch ($this->message_type) {
+ case 'alt':
+ case 'alt_inline':
+ case 'alt_attach':
+ case 'alt_inline_attach':
+ $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
+ break;
+ default:
+ $this->Body = $this->wrapText($this->Body, $this->WordWrap);
+ break;
+ }
+ }
+
+ /**
+ * Assemble message headers.
+ * @access public
+ * @return string The assembled headers
+ */
+ public function createHeader()
+ {
+ $result = '';
+
+ // Set the boundaries
+ $uniq_id = md5(uniqid(time()));
+ $this->boundary[1] = 'b1_' . $uniq_id;
+ $this->boundary[2] = 'b2_' . $uniq_id;
+ $this->boundary[3] = 'b3_' . $uniq_id;
+
+ if ($this->MessageDate == '') {
+ $result .= $this->headerLine('Date', self::rfcDate());
+ } else {
+ $result .= $this->headerLine('Date', $this->MessageDate);
+ }
+
+ if ($this->ReturnPath) {
+ $result .= $this->headerLine('Return-Path', '<' . trim($this->ReturnPath) . '>');
+ } elseif ($this->Sender == '') {
+ $result .= $this->headerLine('Return-Path', '<' . trim($this->From) . '>');
+ } else {
+ $result .= $this->headerLine('Return-Path', '<' . trim($this->Sender) . '>');
+ }
+
+ // To be created automatically by mail()
+ if ($this->Mailer != 'mail') {
+ if ($this->SingleTo === true) {
+ foreach ($this->to as $t) {
+ $this->SingleToArray[] = $this->addrFormat($t);
+ }
+ } else {
+ if (count($this->to) > 0) {
+ $result .= $this->addrAppend('To', $this->to);
+ } elseif (count($this->cc) == 0) {
+ $result .= $this->headerLine('To', 'undisclosed-recipients:;');
+ }
+ }
+ }
+
+ $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
+
+ // sendmail and mail() extract Cc from the header before sending
+ if (count($this->cc) > 0) {
+ $result .= $this->addrAppend('Cc', $this->cc);
+ }
+
+ // sendmail and mail() extract Bcc from the header before sending
+ if ((
+ $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
+ )
+ and count($this->bcc) > 0
+ ) {
+ $result .= $this->addrAppend('Bcc', $this->bcc);
+ }
+
+ if (count($this->ReplyTo) > 0) {
+ $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
+ }
+
+ // mail() sets the subject itself
+ if ($this->Mailer != 'mail') {
+ $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
+ }
+
+ if ($this->MessageID != '') {
+ $this->lastMessageID = $this->MessageID;
+ } else {
+ $this->lastMessageID = sprintf("<%s@%s>", $uniq_id, $this->ServerHostname());
+ }
+ $result .= $this->HeaderLine('Message-ID', $this->lastMessageID);
+ $result .= $this->headerLine('X-Priority', $this->Priority);
+ if ($this->XMailer == '') {
+ $result .= $this->headerLine(
+ 'X-Mailer',
+ 'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer/)'
+ );
+ } else {
+ $myXmailer = trim($this->XMailer);
+ if ($myXmailer) {
+ $result .= $this->headerLine('X-Mailer', $myXmailer);
+ }
+ }
+
+ if ($this->ConfirmReadingTo != '') {
+ $result .= $this->headerLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
+ }
+
+ // Add custom headers
+ for ($index = 0; $index < count($this->CustomHeader); $index++) {
+ $result .= $this->headerLine(
+ trim($this->CustomHeader[$index][0]),
+ $this->encodeHeader(trim($this->CustomHeader[$index][1]))
+ );
+ }
+ if (!$this->sign_key_file) {
+ $result .= $this->headerLine('MIME-Version', '1.0');
+ $result .= $this->getMailMIME();
+ }
+
+ return $result;
+ }
+
+ /**
+ * Get the message MIME type headers.
+ * @access public
+ * @return string
+ */
+ public function getMailMIME()
+ {
+ $result = '';
+ switch ($this->message_type) {
+ case 'inline':
+ $result .= $this->headerLine('Content-Type', 'multipart/related;');
+ $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
+ break;
+ case 'attach':
+ case 'inline_attach':
+ case 'alt_attach':
+ case 'alt_inline_attach':
+ $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
+ $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
+ break;
+ case 'alt':
+ case 'alt_inline':
+ $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
+ $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
+ break;
+ default:
+ // Catches case 'plain': and case '':
+ $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
+ break;
+ }
+ //RFC1341 part 5 says 7bit is assumed if not specified
+ if ($this->Encoding != '7bit') {
+ $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
+ }
+
+ if ($this->Mailer != 'mail') {
+ $result .= $this->LE;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns the whole MIME message.
+ * Includes complete headers and body.
+ * Only valid post PreSend().
+ * @see PHPMailer::PreSend()
+ * @access public
+ * @return string
+ */
+ public function getSentMIMEMessage()
+ {
+ return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
+ }
+
+
+ /**
+ * Assemble the message body.
+ * Returns an empty string on failure.
+ * @access public
+ * @throws phpmailerException
+ * @return string The assembled message body
+ */
+ public function createBody()
+ {
+ $body = '';
+
+ if ($this->sign_key_file) {
+ $body .= $this->getMailMIME() . $this->LE;
+ }
+
+ $this->setWordWrap();
+
+ switch ($this->message_type) {
+ case 'inline':
+ $body .= $this->getBoundary($this->boundary[1], '', '', '');
+ $body .= $this->encodeString($this->Body, $this->Encoding);
+ $body .= $this->LE . $this->LE;
+ $body .= $this->attachAll('inline', $this->boundary[1]);
+ break;
+ case 'attach':
+ $body .= $this->getBoundary($this->boundary[1], '', '', '');
+ $body .= $this->encodeString($this->Body, $this->Encoding);
+ $body .= $this->LE . $this->LE;
+ $body .= $this->attachAll('attachment', $this->boundary[1]);
+ break;
+ case 'inline_attach':
+ $body .= $this->textLine('--' . $this->boundary[1]);
+ $body .= $this->headerLine('Content-Type', 'multipart/related;');
+ $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
+ $body .= $this->LE;
+ $body .= $this->getBoundary($this->boundary[2], '', '', '');
+ $body .= $this->encodeString($this->Body, $this->Encoding);
+ $body .= $this->LE . $this->LE;
+ $body .= $this->attachAll('inline', $this->boundary[2]);
+ $body .= $this->LE;
+ $body .= $this->attachAll('attachment', $this->boundary[1]);
+ break;
+ case 'alt':
+ $body .= $this->getBoundary($this->boundary[1], '', 'text/plain', '');
+ $body .= $this->encodeString($this->AltBody, $this->Encoding);
+ $body .= $this->LE . $this->LE;
+ $body .= $this->getBoundary($this->boundary[1], '', 'text/html', '');
+ $body .= $this->encodeString($this->Body, $this->Encoding);
+ $body .= $this->LE . $this->LE;
+ if (!empty($this->Ical)) {
+ $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
+ $body .= $this->encodeString($this->Ical, $this->Encoding);
+ $body .= $this->LE . $this->LE;
+ }
+ $body .= $this->endBoundary($this->boundary[1]);
+ break;
+ case 'alt_inline':
+ $body .= $this->getBoundary($this->boundary[1], '', 'text/plain', '');
+ $body .= $this->encodeString($this->AltBody, $this->Encoding);
+ $body .= $this->LE . $this->LE;
+ $body .= $this->textLine('--' . $this->boundary[1]);
+ $body .= $this->headerLine('Content-Type', 'multipart/related;');
+ $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
+ $body .= $this->LE;
+ $body .= $this->getBoundary($this->boundary[2], '', 'text/html', '');
+ $body .= $this->encodeString($this->Body, $this->Encoding);
+ $body .= $this->LE . $this->LE;
+ $body .= $this->attachAll('inline', $this->boundary[2]);
+ $body .= $this->LE;
+ $body .= $this->endBoundary($this->boundary[1]);
+ break;
+ case 'alt_attach':
+ $body .= $this->textLine('--' . $this->boundary[1]);
+ $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
+ $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
+ $body .= $this->LE;
+ $body .= $this->getBoundary($this->boundary[2], '', 'text/plain', '');
+ $body .= $this->encodeString($this->AltBody, $this->Encoding);
+ $body .= $this->LE . $this->LE;
+ $body .= $this->getBoundary($this->boundary[2], '', 'text/html', '');
+ $body .= $this->encodeString($this->Body, $this->Encoding);
+ $body .= $this->LE . $this->LE;
+ $body .= $this->endBoundary($this->boundary[2]);
+ $body .= $this->LE;
+ $body .= $this->attachAll('attachment', $this->boundary[1]);
+ break;
+ case 'alt_inline_attach':
+ $body .= $this->textLine('--' . $this->boundary[1]);
+ $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
+ $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
+ $body .= $this->LE;
+ $body .= $this->getBoundary($this->boundary[2], '', 'text/plain', '');
+ $body .= $this->encodeString($this->AltBody, $this->Encoding);
+ $body .= $this->LE . $this->LE;
+ $body .= $this->textLine('--' . $this->boundary[2]);
+ $body .= $this->headerLine('Content-Type', 'multipart/related;');
+ $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
+ $body .= $this->LE;
+ $body .= $this->getBoundary($this->boundary[3], '', 'text/html', '');
+ $body .= $this->encodeString($this->Body, $this->Encoding);
+ $body .= $this->LE . $this->LE;
+ $body .= $this->attachAll('inline', $this->boundary[3]);
+ $body .= $this->LE;
+ $body .= $this->endBoundary($this->boundary[2]);
+ $body .= $this->LE;
+ $body .= $this->attachAll('attachment', $this->boundary[1]);
+ break;
+ default:
+ // catch case 'plain' and case ''
+ $body .= $this->encodeString($this->Body, $this->Encoding);
+ break;
+ }
+
+ if ($this->isError()) {
+ $body = '';
+ } elseif ($this->sign_key_file) {
+ try {
+ if (!defined('PKCS7_TEXT')) {
+ throw new phpmailerException($this->lang('signing') . ' OpenSSL extension missing.');
+ }
+ //TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
+ $file = tempnam(sys_get_temp_dir(), 'mail');
+ file_put_contents($file, $body); //TODO check this worked
+ $signed = tempnam(sys_get_temp_dir(), 'signed');
+ if (@openssl_pkcs7_sign(
+ $file,
+ $signed,
+ 'file://' . realpath($this->sign_cert_file),
+ array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
+ null
+ )
+ ) {
+ @unlink($file);
+ $body = file_get_contents($signed);
+ @unlink($signed);
+ } else {
+ @unlink($file);
+ @unlink($signed);
+ throw new phpmailerException($this->lang('signing') . openssl_error_string());
+ }
+ } catch (phpmailerException $e) {
+ $body = '';
+ if ($this->exceptions) {
+ throw $e;
+ }
+ }
+ }
+ return $body;
+ }
+
+ /**
+ * Return the start of a message boundary.
+ * @access protected
+ * @param string $boundary
+ * @param string $charSet
+ * @param string $contentType
+ * @param string $encoding
+ * @return string
+ */
+ protected function getBoundary($boundary, $charSet, $contentType, $encoding)
+ {
+ $result = '';
+ if ($charSet == '') {
+ $charSet = $this->CharSet;
+ }
+ if ($contentType == '') {
+ $contentType = $this->ContentType;
+ }
+ if ($encoding == '') {
+ $encoding = $this->Encoding;
+ }
+ $result .= $this->textLine('--' . $boundary);
+ $result .= sprintf("Content-Type: %s; charset=%s", $contentType, $charSet);
+ $result .= $this->LE;
+ $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
+ $result .= $this->LE;
+
+ return $result;
+ }
+
+ /**
+ * Return the end of a message boundary.
+ * @access protected
+ * @param string $boundary
+ * @return string
+ */
+ protected function endBoundary($boundary)
+ {
+ return $this->LE . '--' . $boundary . '--' . $this->LE;
+ }
+
+ /**
+ * Set the message type.
+ * PHPMailer only supports some preset message types,
+ * not arbitrary MIME structures.
+ * @access protected
+ * @return void
+ */
+ protected function setMessageType()
+ {
+ $this->message_type = array();
+ if ($this->alternativeExists()) {
+ $this->message_type[] = "alt";
+ }
+ if ($this->inlineImageExists()) {
+ $this->message_type[] = "inline";
+ }
+ if ($this->attachmentExists()) {
+ $this->message_type[] = "attach";
+ }
+ $this->message_type = implode("_", $this->message_type);
+ if ($this->message_type == "") {
+ $this->message_type = "plain";
+ }
+ }
+
+ /**
+ * Format a header line.
+ * @access public
+ * @param string $name
+ * @param string $value
+ * @return string
+ */
+ public function headerLine($name, $value)
+ {
+ return $name . ': ' . $value . $this->LE;
+ }
+
+ /**
+ * Return a formatted mail line.
+ * @access public
+ * @param string $value
+ * @return string
+ */
+ public function textLine($value)
+ {
+ return $value . $this->LE;
+ }
+
+ /**
+ * Add an attachment from a path on the filesystem.
+ * Returns false if the file could not be found or read.
+ * @param string $path Path to the attachment.
+ * @param string $name Overrides the attachment name.
+ * @param string $encoding File encoding (see $Encoding).
+ * @param string $type File extension (MIME) type.
+ * @param string $disposition Disposition to use
+ * @throws phpmailerException
+ * @return bool
+ */
+ public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
+ {
+ try {
+ if (!@is_file($path)) {
+ throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
+ }
+
+ //If a MIME type is not specified, try to work it out from the file name
+ if ($type == '') {
+ $type = self::filenameToType($path);
+ }
+
+ $filename = basename($path);
+ if ($name == '') {
+ $name = $filename;
+ }
+
+ $this->attachment[] = array(
+ 0 => $path,
+ 1 => $filename,
+ 2 => $name,
+ 3 => $encoding,
+ 4 => $type,
+ 5 => false, // isStringAttachment
+ 6 => $disposition,
+ 7 => 0
+ );
+
+ } catch (phpmailerException $e) {
+ $this->setError($e->getMessage());
+ $this->edebug($e->getMessage());
+ if ($this->exceptions) {
+ throw $e;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Return the array of attachments.
+ * @return array
+ */
+ public function getAttachments()
+ {
+ return $this->attachment;
+ }
+
+ /**
+ * Attach all file, string, and binary attachments to the message.
+ * Returns an empty string on failure.
+ * @access protected
+ * @param string $disposition_type
+ * @param string $boundary
+ * @return string
+ */
+ protected function attachAll($disposition_type, $boundary)
+ {
+ // Return text of body
+ $mime = array();
+ $cidUniq = array();
+ $incl = array();
+
+ // Add all attachments
+ foreach ($this->attachment as $attachment) {
+ // Check if it is a valid disposition_filter
+ if ($attachment[6] == $disposition_type) {
+ // Check for string attachment
+ $string = '';
+ $path = '';
+ $bString = $attachment[5];
+ if ($bString) {
+ $string = $attachment[0];
+ } else {
+ $path = $attachment[0];
+ }
+
+ $inclhash = md5(serialize($attachment));
+ if (in_array($inclhash, $incl)) {
+ continue;
+ }
+ $incl[] = $inclhash;
+ $name = $attachment[2];
+ $encoding = $attachment[3];
+ $type = $attachment[4];
+ $disposition = $attachment[6];
+ $cid = $attachment[7];
+ if ($disposition == 'inline' && isset($cidUniq[$cid])) {
+ continue;
+ }
+ $cidUniq[$cid] = true;
+
+ $mime[] = sprintf("--%s%s", $boundary, $this->LE);
+ $mime[] = sprintf(
+ "Content-Type: %s; name=\"%s\"%s",
+ $type,
+ $this->encodeHeader($this->secureHeader($name)),
+ $this->LE
+ );
+ $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
+
+ if ($disposition == 'inline') {
+ $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
+ }
+
+ // If a filename contains any of these chars, it should be quoted,
+ // but not otherwise: RFC2183 & RFC2045 5.1
+ // Fixes a warning in IETF's msglint MIME checker
+ // Allow for bypassing the Content-Disposition header totally
+ if (!(empty($disposition))) {
+ if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $name)) {
+ $mime[] = sprintf(
+ "Content-Disposition: %s; filename=\"%s\"%s",
+ $disposition,
+ $this->encodeHeader($this->secureHeader($name)),
+ $this->LE . $this->LE
+ );
+ } else {
+ $mime[] = sprintf(
+ "Content-Disposition: %s; filename=%s%s",
+ $disposition,
+ $this->encodeHeader($this->secureHeader($name)),
+ $this->LE . $this->LE
+ );
+ }
+ } else {
+ $mime[] = $this->LE;
+ }
+
+ // Encode as string attachment
+ if ($bString) {
+ $mime[] = $this->encodeString($string, $encoding);
+ if ($this->isError()) {
+ return '';
+ }
+ $mime[] = $this->LE . $this->LE;
+ } else {
+ $mime[] = $this->encodeFile($path, $encoding);
+ if ($this->isError()) {
+ return '';
+ }
+ $mime[] = $this->LE . $this->LE;
+ }
+ }
+ }
+
+ $mime[] = sprintf("--%s--%s", $boundary, $this->LE);
+
+ return implode("", $mime);
+ }
+
+ /**
+ * Encode a file attachment in requested format.
+ * Returns an empty string on failure.
+ * @param string $path The full path to the file
+ * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
+ * @throws phpmailerException
+ * @see EncodeFile(encodeFile
+ * @access protected
+ * @return string
+ */
+ protected function encodeFile($path, $encoding = 'base64')
+ {
+ try {
+ if (!is_readable($path)) {
+ throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
+ }
+ $magic_quotes = get_magic_quotes_runtime();
+ if ($magic_quotes) {
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+ set_magic_quotes_runtime(0);
+ } else {
+ ini_set('magic_quotes_runtime', 0);
+ }
+ }
+ $file_buffer = file_get_contents($path);
+ $file_buffer = $this->encodeString($file_buffer, $encoding);
+ if ($magic_quotes) {
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+ set_magic_quotes_runtime($magic_quotes);
+ } else {
+ ini_set('magic_quotes_runtime', $magic_quotes);
+ }
+ }
+ return $file_buffer;
+ } catch (Exception $e) {
+ $this->setError($e->getMessage());
+ return '';
+ }
+ }
+
+ /**
+ * Encode a string in requested format.
+ * Returns an empty string on failure.
+ * @param string $str The text to encode
+ * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
+ * @access public
+ * @return string
+ */
+ public function encodeString($str, $encoding = 'base64')
+ {
+ $encoded = '';
+ switch (strtolower($encoding)) {
+ case 'base64':
+ $encoded = chunk_split(base64_encode($str), 76, $this->LE);
+ break;
+ case '7bit':
+ case '8bit':
+ $encoded = $this->fixEOL($str);
+ //Make sure it ends with a line break
+ if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
+ $encoded .= $this->LE;
+ }
+ break;
+ case 'binary':
+ $encoded = $str;
+ break;
+ case 'quoted-printable':
+ $encoded = $this->encodeQP($str);
+ break;
+ default:
+ $this->setError($this->lang('encoding') . $encoding);
+ break;
+ }
+ return $encoded;
+ }
+
+ /**
+ * Encode a header string optimally.
+ * Picks shortest of Q, B, quoted-printable or none.
+ * @access public
+ * @param string $str
+ * @param string $position
+ * @return string
+ */
+ public function encodeHeader($str, $position = 'text')
+ {
+ $x = 0;
+ switch (strtolower($position)) {
+ case 'phrase':
+ if (!preg_match('/[\200-\377]/', $str)) {
+ // Can't use addslashes as we don't know what value has magic_quotes_sybase
+ $encoded = addcslashes($str, "\0..\37\177\\\"");
+ if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
+ return ($encoded);
+ } else {
+ return ("\"$encoded\"");
+ }
+ }
+ $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
+ break;
+ /** @noinspection PhpMissingBreakStatementInspection */
+ case 'comment':
+ $x = preg_match_all('/[()"]/', $str, $matches);
+ // Intentional fall-through
+ case 'text':
+ default:
+ $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
+ break;
+ }
+
+ if ($x == 0) { //There are no chars that need encoding
+ return ($str);
+ }
+
+ $maxlen = 75 - 7 - strlen($this->CharSet);
+ // Try to select the encoding which should produce the shortest output
+ if ($x > strlen($str) / 3) {
+ //More than a third of the content will need encoding, so B encoding will be most efficient
+ $encoding = 'B';
+ if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
+ // Use a custom function which correctly encodes and wraps long
+ // multibyte strings without breaking lines within a character
+ $encoded = $this->base64EncodeWrapMB($str, "\n");
+ } else {
+ $encoded = base64_encode($str);
+ $maxlen -= $maxlen % 4;
+ $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
+ }
+ } else {
+ $encoding = 'Q';
+ $encoded = $this->encodeQ($str, $position);
+ $encoded = $this->wrapText($encoded, $maxlen, true);
+ $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
+ }
+
+ $encoded = preg_replace('/^(.*)$/m', " =?" . $this->CharSet . "?$encoding?\\1?=", $encoded);
+ $encoded = trim(str_replace("\n", $this->LE, $encoded));
+
+ return $encoded;
+ }
+
+ /**
+ * Check if a string contains multi-byte characters.
+ * @access public
+ * @param string $str multi-byte text to wrap encode
+ * @return bool
+ */
+ public function hasMultiBytes($str)
+ {
+ if (function_exists('mb_strlen')) {
+ return (strlen($str) > mb_strlen($str, $this->CharSet));
+ } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
+ return false;
+ }
+ }
+
+ /**
+ * Encode and wrap long multibyte strings for mail headers
+ * without breaking lines within a character.
+ * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
+ * @access public
+ * @param string $str multi-byte text to wrap encode
+ * @param string $lf string to use as linefeed/end-of-line
+ * @return string
+ */
+ public function base64EncodeWrapMB($str, $lf = null)
+ {
+ $start = "=?" . $this->CharSet . "?B?";
+ $end = "?=";
+ $encoded = "";
+ if ($lf === null) {
+ $lf = $this->LE;
+ }
+
+ $mb_length = mb_strlen($str, $this->CharSet);
+ // Each line must have length <= 75, including $start and $end
+ $length = 75 - strlen($start) - strlen($end);
+ // Average multi-byte ratio
+ $ratio = $mb_length / strlen($str);
+ // Base64 has a 4:3 ratio
+ $avgLength = floor($length * $ratio * .75);
+
+ for ($i = 0; $i < $mb_length; $i += $offset) {
+ $lookBack = 0;
+ do {
+ $offset = $avgLength - $lookBack;
+ $chunk = mb_substr($str, $i, $offset, $this->CharSet);
+ $chunk = base64_encode($chunk);
+ $lookBack++;
+ } while (strlen($chunk) > $length);
+ $encoded .= $chunk . $lf;
+ }
+
+ // Chomp the last linefeed
+ $encoded = substr($encoded, 0, -strlen($lf));
+ return $encoded;
+ }
+
+ /**
+ * Encode a string in quoted-printable format.
+ * According to RFC2045 section 6.7.
+ * @access public
+ * @param string $string The text to encode
+ * @param integer $line_max Number of chars allowed on a line before wrapping
+ * @return string
+ * @link PHP version adapted from http://www.php.net/manual/en/function.quoted-printable-decode.php#89417
+ */
+ public function encodeQP($string, $line_max = 76)
+ {
+ if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3)
+ return $this->fixEOL(quoted_printable_encode($string));
+ }
+ //Fall back to a pure PHP implementation
+ $string = str_replace(
+ array('%20', '%0D%0A.', '%0D%0A', '%'),
+ array(' ', "\r\n=2E", "\r\n", '='),
+ rawurlencode($string)
+ );
+ $string = preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
+ return $this->fixEOL($string);
+ }
+
+ /**
+ * Backward compatibility wrapper for an old QP encoding function that was removed.
+ * @see PHPMailer::encodeQP()
+ * @access public
+ * @param string $string
+ * @param integer $line_max
+ * @param bool $space_conv
+ * @return string
+ * @deprecated Use encodeQP instead.
+ */
+ public function encodeQPphp(
+ $string,
+ $line_max = 76,
+ /** @noinspection PhpUnusedParameterInspection */ $space_conv = false
+ ) {
+ return $this->encodeQP($string, $line_max);
+ }
+
+ /**
+ * Encode a string using Q encoding.
+ * @link http://tools.ietf.org/html/rfc2047
+ * @param string $str the text to encode
+ * @param string $position Where the text is going to be used, see the RFC for what that means
+ * @access public
+ * @return string
+ */
+ public function encodeQ($str, $position = 'text')
+ {
+ //There should not be any EOL in the string
+ $pattern = '';
+ $encoded = str_replace(array("\r", "\n"), '', $str);
+ switch (strtolower($position)) {
+ case 'phrase':
+ //RFC 2047 section 5.3
+ $pattern = '^A-Za-z0-9!*+\/ -';
+ break;
+ /** @noinspection PhpMissingBreakStatementInspection */
+ case 'comment':
+ //RFC 2047 section 5.2
+ $pattern = '\(\)"';
+ //intentional fall-through
+ //for this reason we build the $pattern without including delimiters and []
+ case 'text':
+ default:
+ //RFC 2047 section 5.1
+ //Replace every high ascii, control, =, ? and _ characters
+ $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
+ break;
+ }
+ $matches = array();
+ if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
+ //If the string contains an '=', make sure it's the first thing we replace
+ //so as to avoid double-encoding
+ $s = array_search('=', $matches[0]);
+ if ($s !== false) {
+ unset($matches[0][$s]);
+ array_unshift($matches[0], '=');
+ }
+ foreach (array_unique($matches[0]) as $char) {
+ $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
+ }
+ }
+ //Replace every spaces to _ (more readable than =20)
+ return str_replace(' ', '_', $encoded);
+ }
+
+
+ /**
+ * Add a string or binary attachment (non-filesystem).
+ * This method can be used to attach ascii or binary data,
+ * such as a BLOB record from a database.
+ * @param string $string String attachment data.
+ * @param string $filename Name of the attachment.
+ * @param string $encoding File encoding (see $Encoding).
+ * @param string $type File extension (MIME) type.
+ * @param string $disposition Disposition to use
+ * @return void
+ */
+ public function addStringAttachment(
+ $string,
+ $filename,
+ $encoding = 'base64',
+ $type = '',
+ $disposition = 'attachment'
+ ) {
+ //If a MIME type is not specified, try to work it out from the file name
+ if ($type == '') {
+ $type = self::filenameToType($filename);
+ }
+ // Append to $attachment array
+ $this->attachment[] = array(
+ 0 => $string,
+ 1 => $filename,
+ 2 => basename($filename),
+ 3 => $encoding,
+ 4 => $type,
+ 5 => true, // isStringAttachment
+ 6 => $disposition,
+ 7 => 0
+ );
+ }
+
+ /**
+ * Add an embedded (inline) attachment from a file.
+ * This can include images, sounds, and just about any other document type.
+ * These differ from 'regular' attachmants in that they are intended to be
+ * displayed inline with the message, not just attached for download.
+ * This is used in HTML messages that embed the images
+ * the HTML refers to using the $cid value.
+ * @param string $path Path to the attachment.
+ * @param string $cid Content ID of the attachment; Use this to reference
+ * the content when using an embedded image in HTML.
+ * @param string $name Overrides the attachment name.
+ * @param string $encoding File encoding (see $Encoding).
+ * @param string $type File MIME type.
+ * @param string $disposition Disposition to use
+ * @return bool True on successfully adding an attachment
+ */
+ public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
+ {
+ if (!@is_file($path)) {
+ $this->setError($this->lang('file_access') . $path);
+ return false;
+ }
+
+ //If a MIME type is not specified, try to work it out from the file name
+ if ($type == '') {
+ $type = self::filenameToType($path);
+ }
+
+ $filename = basename($path);
+ if ($name == '') {
+ $name = $filename;
+ }
+
+ // Append to $attachment array
+ $this->attachment[] = array(
+ 0 => $path,
+ 1 => $filename,
+ 2 => $name,
+ 3 => $encoding,
+ 4 => $type,
+ 5 => false, // isStringAttachment
+ 6 => $disposition,
+ 7 => $cid
+ );
+ return true;
+ }
+
+ /**
+ * Add an embedded stringified attachment.
+ * This can include images, sounds, and just about any other document type.
+ * Be sure to set the $type to an image type for images:
+ * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
+ * @param string $string The attachment binary data.
+ * @param string $cid Content ID of the attachment; Use this to reference
+ * the content when using an embedded image in HTML.
+ * @param string $name
+ * @param string $encoding File encoding (see $Encoding).
+ * @param string $type MIME type.
+ * @param string $disposition Disposition to use
+ * @return bool True on successfully adding an attachment
+ */
+ public function addStringEmbeddedImage(
+ $string,
+ $cid,
+ $name = '',
+ $encoding = 'base64',
+ $type = '',
+ $disposition = 'inline'
+ ) {
+ //If a MIME type is not specified, try to work it out from the name
+ if ($type == '') {
+ $type = self::filenameToType($name);
+ }
+
+ // Append to $attachment array
+ $this->attachment[] = array(
+ 0 => $string,
+ 1 => $name,
+ 2 => $name,
+ 3 => $encoding,
+ 4 => $type,
+ 5 => true, // isStringAttachment
+ 6 => $disposition,
+ 7 => $cid
+ );
+ return true;
+ }
+
+ /**
+ * Check if an inline attachment is present.
+ * @access public
+ * @return bool
+ */
+ public function inlineImageExists()
+ {
+ foreach ($this->attachment as $attachment) {
+ if ($attachment[6] == 'inline') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if an attachment (non-inline) is present.
+ * @return bool
+ */
+ public function attachmentExists()
+ {
+ foreach ($this->attachment as $attachment) {
+ if ($attachment[6] == 'attachment') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if this message has an alternative body set.
+ * @return bool
+ */
+ public function alternativeExists()
+ {
+ return !empty($this->AltBody);
+ }
+
+ /**
+ * Clear all To recipients.
+ * @return void
+ */
+ public function clearAddresses()
+ {
+ foreach ($this->to as $to) {
+ unset($this->all_recipients[strtolower($to[0])]);
+ }
+ $this->to = array();
+ }
+
+ /**
+ * Clear all CC recipients.
+ * @return void
+ */
+ public function clearCCs()
+ {
+ foreach ($this->cc as $cc) {
+ unset($this->all_recipients[strtolower($cc[0])]);
+ }
+ $this->cc = array();
+ }
+
+ /**
+ * Clear all BCC recipients.
+ * @return void
+ */
+ public function clearBCCs()
+ {
+ foreach ($this->bcc as $bcc) {
+ unset($this->all_recipients[strtolower($bcc[0])]);
+ }
+ $this->bcc = array();
+ }
+
+ /**
+ * Clear all ReplyTo recipients.
+ * @return void
+ */
+ public function clearReplyTos()
+ {
+ $this->ReplyTo = array();
+ }
+
+ /**
+ * Clear all recipient types.
+ * @return void
+ */
+ public function clearAllRecipients()
+ {
+ $this->to = array();
+ $this->cc = array();
+ $this->bcc = array();
+ $this->all_recipients = array();
+ }
+
+ /**
+ * Clear all filesystem, string, and binary attachments.
+ * @return void
+ */
+ public function clearAttachments()
+ {
+ $this->attachment = array();
+ }
+
+ /**
+ * Clear all custom headers.
+ * @return void
+ */
+ public function clearCustomHeaders()
+ {
+ $this->CustomHeader = array();
+ }
+
+ /**
+ * Add an error message to the error container.
+ * @access protected
+ * @param string $msg
+ * @return void
+ */
+ protected function setError($msg)
+ {
+ $this->error_count++;
+ if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
+ $lasterror = $this->smtp->getError();
+ if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) {
+ $msg .= '