function send_command($command, $piped = false) { if ($piped) { $final_command = ''; foreach ($command as $v) { $final_command .= 'A' . $this->command_number() . ' ' . $v; } $command = $final_command; } else { $command = 'A' . $this->command_number() . ' ' . $command; } if (!is_resource($this->handle)) { throw new \Exception("Lost connection to " . $this->server); } $this->lastCommand = $command; if (!fputs($this->handle, $command)) { throw new \Exception("Lost connection to " . $this->server); // eturn false; } if (!empty(\GO::session()->values['debugSql'])) { \GO::debug("S: " . $command); } $this->commands[trim($command)] = \GO\Base\Util\Date::getmicrotime(); }
/** * Handles authentication. You can optionally set * $this->starttls or $this->auth to CRAM-MD5 * * @param <type> $username * @param <type> $pass * @return <type> */ private function authenticate($username, $pass) { if ($this->starttls) { $command = "STARTTLS\r\n"; $this->send_command($command); $response = $this->get_response(); if (!empty($response)) { $end = array_pop($response); if (substr($end, 0, strlen('A' . $this->command_count . ' OK')) == 'A' . $this->command_count . ' OK') { stream_socket_enable_crypto($this->handle, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); } } } switch (strtolower($this->auth)) { case 'cram-md5': $this->banner = fgets($this->handle, 1024); $cram1 = 'A' . $this->command_number() . ' AUTHENTICATE CRAM-MD5' . "\r\n"; fputs($this->handle, $cram1); $this->commands[trim($cram1)] = \GO\Base\Util\Date::getmicrotime(); $response = fgets($this->handle, 1024); $this->responses[] = $response; $challenge = base64_decode(substr(trim($response), 1)); $pass .= str_repeat(chr(0x0), 64 - strlen($pass)); $ipad = str_repeat(chr(0x36), 64); $opad = str_repeat(chr(0x5c), 64); $digest = bin2hex(pack("H*", md5(($pass ^ $opad) . pack("H*", md5(($pass ^ $ipad) . $challenge))))); $challenge_response = base64_encode($username . ' ' . $digest); $this->commands[trim($challenge_response)] = \GO\Base\Util\Date::getmicrotime(); fputs($this->handle, $challenge_response . "\r\n"); break; default: $login = '******' . $this->command_number() . ' LOGIN "' . $this->_escape($username) . '" "' . $this->_escape($pass) . "\"\r\n"; $this->commands[trim(str_replace($pass, 'xxxx', $login))] = \GO\Base\Util\Date::getmicrotime(); fputs($this->handle, $login); break; } $res = $this->get_response(); $authed = false; if (is_array($res) && !empty($res)) { $response = array_pop($res); //Sometimes an extra empty line comes along if (!$response && count($res) == 2) { $response = array_pop($res); } $this->short_responses[$response] = \GO\Base\Util\Date::getmicrotime(); if (!$this->auth) { if (isset($res[1])) { $this->banner = $res[1]; } if (isset($res[0])) { $this->banner = $res[0]; } } if (stristr($response, 'A' . $this->command_count . ' OK')) { $authed = true; $this->state = 'authed'; //some imap servers like dovecot respond with the capability after login. //Set this in the session so we don't need to do an extra capability command. if (($startpos = strpos($response, 'CAPABILITY')) !== false) { \GO::debug("Use capability from login"); $endpos = strpos($response, ']', $startpos); if ($endpos) { $capability = substr($response, $startpos, $endpos - $startpos); \GO::session()->values['GO_IMAP'][$this->server]['imap_capability'] = $capability; } } } else { // if(!\GO::config()->debug) // $this->errors[]=$response; throw new ImapAuthenticationFailedException('Authententication failed for user ' . $username . ' on IMAP server ' . $this->server . "\n\n" . $response); } } return $authed; }
/** * Find models * * Example usage: * * <code> * //create new find params object * $params = FindParams::newInstance() * ->joinCustomFields() * ->order('due_time','ASC'); * * //select all from tasklist id = 1 * $params->getCriteria()->addCondition('tasklist_id,1); * * //find the tasks * $stmt = \GO\Tasks\Model\Task::model()->find($params); * * //print the names * while($task = $stmt->fetch()){ * echo $task->name.'<br>'; * } * </code> * * * @param FindParams $params * @return static ActiveStatement */ public function find($params = array()) { if (!is_array($params)) { if (!$params instanceof FindParams) { throw new \Exception('$params parameter for find() must be instance of FindParams'); } if ($params->getParam("export")) { GO::session()->values[$params->getParam("export")] = array('name' => $params->getParam("export"), 'model' => $this->className(), 'findParams' => $params, 'totalizeColumns' => $params->getParam('export_totalize_columns')); } //it must be a FindParams object $params = $params->getParams(); } if (!empty($params['single'])) { unset($params['single']); return $this->findSingle($params); } if (!empty($params['debugSql'])) { $this->_debugSql = true; //GO::debug($params); } else { $this->_debugSql = !empty(GO::session()->values['debugSql']); } // $this->_debugSql=true; if (GO::$ignoreAclPermissions) { $params['ignoreAcl'] = true; } if (empty($params['userId'])) { $params['userId'] = !empty(GO::session()->values['user_id']) ? GO::session()->values['user_id'] : 1; } if ($this->aclField() && (empty($params['ignoreAcl']) || !empty($params['joinAclFieldTable']))) { $aclJoinProps = $this->_getAclJoinProps(); if (isset($aclJoinProps['relation'])) { $params['joinRelations'][$aclJoinProps['relation']['name']] = array('name' => $aclJoinProps['relation']['name'], 'type' => 'INNER'); } } $select = "SELECT "; if (!empty($params['distinct'])) { $select .= "DISTINCT "; } //Unique query ID for storing found rows in session $queryUid = $this->_getFindQueryUid($params); if (!empty($params['calcFoundRows']) && !empty($params['limit']) && (empty($params['start']) || !isset(GO::session()->values[$queryUid]))) { //TODO: This is MySQL only code if ($this->useSqlCalcFoundRows) { $select .= "SQL_CALC_FOUND_ROWS "; } $calcFoundRows = true; } else { $calcFoundRows = false; } // $select .= "SQL_NO_CACHE "; if (empty($params['fields'])) { $params['fields'] = $this->getDefaultFindSelectFields(isset($params['limit']) && $params['limit'] == 1); } $fields = $params['fields'] . ' '; $joinRelationSelectFields = ''; $joinRelationjoins = ''; if (!empty($params['joinRelations'])) { /* * Relational attributes are fetch as relationname@attribute or * * relation1@relation2@attribute. * * In the ActiveRecord constructor these attributes are filtered into a relatedCache array. * * example query with joinRelation('order.book') on a \GO\Billing\Model\Item: * * SELECT `t`.`id`, `t`.`order_id`, `t`.`product_id`, `t`.`unit_cost`, `t`.`unit_price`, `t`.`unit_list`, `t`.`unit_total`, `t`.`amount`, `t`.`vat`, `t`.`discount`, `t`.`sort_order`, `t`.`cost_code`, `t`.`markup`, `t`.`order_at_supplier`, `t`.`order_at_supplier_company_id`, `t`.`amount_delivered`, `t`.`unit`, `t`.`item_group_id`, `t`.`extra_cost_status_id` , `order`.`id` AS `order@id`, `order`.`project_id` AS `order@project_id`, `order`.`status_id` AS `order@status_id`, `order`.`book_id` AS `order@book_id`, `order`.`language_id` AS `order@language_id`, `order`.`user_id` AS `order@user_id`, `order`.`order_id` AS `order@order_id`, `order`.`po_id` AS `order@po_id`, `order`.`company_id` AS `order@company_id`, `order`.`contact_id` AS `order@contact_id`, `order`.`ctime` AS `order@ctime`, `order`.`mtime` AS `order@mtime`, `order`.`btime` AS `order@btime`, `order`.`ptime` AS `order@ptime`, `order`.`costs` AS `order@costs`, `order`.`subtotal` AS `order@subtotal`, `order`.`vat` AS `order@vat`, `order`.`total` AS `order@total`, `order`.`authcode` AS `order@authcode`, `order`.`frontpage_text` AS `order@frontpage_text`, `order`.`customer_name` AS `order@customer_name`, `order`.`customer_to` AS `order@customer_to`, `order`.`customer_salutation` AS `order@customer_salutation`, `order`.`customer_contact_name` AS `order@customer_contact_name`, `order`.`customer_address` AS `order@customer_address`, `order`.`customer_address_no` AS `order@customer_address_no`, `order`.`customer_zip` AS `order@customer_zip`, `order`.`customer_city` AS `order@customer_city`, `order`.`customer_state` AS `order@customer_state`, `order`.`customer_country` AS `order@customer_country`, `order`.`customer_vat_no` AS `order@customer_vat_no`, `order`.`customer_crn` AS `order@customer_crn`, `order`.`customer_email` AS `order@customer_email`, `order`.`customer_extra` AS `order@customer_extra`, `order`.`webshop_id` AS `order@webshop_id`, `order`.`recur_type` AS `order@recur_type`, `order`.`payment_method` AS `order@payment_method`, `order`.`recurred_order_id` AS `order@recurred_order_id`, `order`.`reference` AS `order@reference`, `order`.`order_bonus_points` AS `order@order_bonus_points`, `order`.`pagebreak` AS `order@pagebreak`, `order`.`files_folder_id` AS `order@files_folder_id`, `order`.`cost_code` AS `order@cost_code`, `order`.`for_warehouse` AS `order@for_warehouse`, `order`.`dtime` AS `order@dtime`, `book`.`id` AS `order@book@id`, `book`.`user_id` AS `order@book@user_id`, `book`.`name` AS `order@book@name`, `book`.`acl_id` AS `order@book@acl_id`, `book`.`order_id_prefix` AS `order@book@order_id_prefix`, `book`.`show_statuses` AS `order@book@show_statuses`, `book`.`next_id` AS `order@book@next_id`, `book`.`default_vat` AS `order@book@default_vat`, `book`.`currency` AS `order@book@currency`, `book`.`order_csv_template` AS `order@book@order_csv_template`, `book`.`item_csv_template` AS `order@book@item_csv_template`, `book`.`country` AS `order@book@country`, `book`.`bcc` AS `order@book@bcc`, `book`.`call_after_days` AS `order@book@call_after_days`, `book`.`sender_email` AS `order@book@sender_email`, `book`.`sender_name` AS `order@book@sender_name`, `book`.`is_purchase_orders_book` AS `order@book@is_purchase_orders_book`, `book`.`backorder_status_id` AS `order@book@backorder_status_id`, `book`.`delivered_status_id` AS `order@book@delivered_status_id`, `book`.`reversal_status_id` AS `order@book@reversal_status_id`, `book`.`addressbook_id` AS `order@book@addressbook_id`, `book`.`files_folder_id` AS `order@book@files_folder_id`, `book`.`import_status_id` AS `order@book@import_status_id`, `book`.`import_notify_customer` AS `order@book@import_notify_customer`, `book`.`import_duplicate_to_book` AS `order@book@import_duplicate_to_book`, `book`.`import_duplicate_status_id` AS `order@book@import_duplicate_status_id` FROM `bs_items` t INNER JOIN `bs_orders` `order` ON (`order`.`id`=`t`.`order_id`) INNER JOIN `bs_books` `book` ON (`book`.`id`=`order`.`book_id`) WHERE 1 AND `t`.`product_id` = "426" AND `order`.`btime` < "1369143782" AND `order`.`btime` > "0" ORDER BY `book`.`name` ASC ,`order`.`btime` DESC * */ foreach ($params['joinRelations'] as $joinRelation) { $names = explode('.', $joinRelation['name']); $relationModel = $this; $relationAlias = 't'; $attributePrefix = ''; foreach ($names as $name) { $r = $relationModel->getRelation($name); $attributePrefix .= $name . '@'; if (!$r) { throw new \Exception("Can't join non existing relation '" . $name . '"'); } $model = GO::getModel($r['model']); $joinRelationjoins .= "\n" . $joinRelation['type'] . " JOIN `" . $model->tableName() . '` `' . $name . '` ON ('; switch ($r['type']) { case self::BELONGS_TO: $joinRelationjoins .= '`' . $name . '`.`' . $model->primaryKey() . '`=`' . $relationAlias . '`.`' . $r['field'] . '`'; break; case self::HAS_ONE: case self::HAS_MANY: if (is_array($r['field'])) { $conditions = array(); foreach ($r['field'] as $my => $foreign) { $conditions[] = '`' . $name . '`.`' . $foreign . '`=t.`' . $my . '`'; } $joinRelationjoins .= implode(' AND ', $conditions); } else { $joinRelationjoins .= '`' . $name . '`.`' . $r['field'] . '`=t.`' . $this->primaryKey() . '`'; } break; default: throw new \Exception("The relation type of " . $name . " is not supported by joinRelation or groupRelation"); break; } $joinRelationjoins .= ') '; //if a diffent fetch class is passed then we should not join the relational fields because it makes no sense. //\GO\Base\Model\Grouped does this for example. if (empty($params['fetchClass'])) { $cols = $model->getColumns(); foreach ($cols as $field => $props) { $joinRelationSelectFields .= ",\n`" . $name . '`.`' . $field . '` AS `' . $attributePrefix . $field . '`'; } } $relationModel = $model; $relationAlias = $name; } } } $joinCf = !empty($params['joinCustomFields']) && $this->customfieldsModel() && GO::modules()->customfields && GO::modules()->customfields->permissionLevel; if ($joinCf) { $cfModel = GO::getModel($this->customfieldsModel()); $selectFields = $cfModel->getDefaultFindSelectFields(isset($params['limit']) && $params['limit'] == 1, 'cf'); if (!empty($selectFields)) { $fields .= ", " . $selectFields; } } $fields .= $joinRelationSelectFields; if (!empty($params['groupRelationSelect'])) { $fields .= ",\n" . $params['groupRelationSelect']; } $from = "\nFROM `" . $this->tableName() . "` t " . $joinRelationjoins; $joins = ""; if (!empty($params['linkModel'])) { //passed in case of a MANY_MANY relation query $linkModel = new $params['linkModel'](); $primaryKeys = $linkModel->primaryKey(); if (!is_array($primaryKeys)) { throw new \Exception("Fatal error: Primary key of linkModel '" . $params['linkModel'] . "' in relation '" . $params['relation'] . "' should be an array."); } $remoteField = $primaryKeys[0] == $params['linkModelLocalField'] ? $primaryKeys[1] : $primaryKeys[0]; $joins .= "\nINNER JOIN `" . $linkModel->tableName() . "` link_t ON t.`" . $this->primaryKey() . "`= link_t." . $remoteField . ' '; } if ($joinCf) { $joins .= "\nLEFT JOIN `" . $cfModel->tableName() . "` cf ON cf.model_id=t.id "; } if (isset($aclJoinProps) && empty($params['ignoreAcl'])) { $joins .= $this->_appendAclJoin($params, $aclJoinProps); } if (isset($params['join'])) { $joins .= "\n" . $params['join']; } //testing with subquery // if($this->aclField() && empty($params['ignoreAcl'])){ // //quick and dirty way to use and in next sql build blocks // $sql .= "\nWHERE "; // // $sql .= "\nEXISTS (SELECT level FROM go_acl WHERE `".$aclJoin['table']."`.`".$aclJoin['aclField']."` = go_acl.acl_id"; // if(isset($params['permissionLevel']) && $params['permissionLevel']>\GO\Base\Model\Acl::READ_PERMISSION){ // $sql .= " AND go_acl.level>=".intval($params['permissionLevel']); // } // // $groupIds = \GO\Base\Model\User::getGroupIds($params['userId']); // // if(!empty($params['ignoreAdminGroup'])){ // $key = array_search(GO::config()->group_root, $groupIds); // if($key!==false) // unset($groupIds[$key]); // } // // // $sql .= " AND (go_acl.user_id=".intval($params['userId'])." OR go_acl.group_id IN (".implode(',',$groupIds)."))) "; // }else // { $where = "\nWHERE 1 "; // } if (isset($params['criteriaObject'])) { $conditionSql = $params['criteriaObject']->getCondition(); if (!empty($conditionSql)) { $where .= "\nAND" . $conditionSql; } } // if(!empty($params['criteriaSql'])) // $sql .= $params['criteriaSql']; $where = self::_appendByParamsToSQL($where, $params); if (isset($params['where'])) { $where .= "\nAND " . $params['where']; } if (isset($linkModel)) { //$primaryKeys = $linkModel->primaryKey(); //$remoteField = $primaryKeys[0]==$params['linkModelLocalField'] ? $primaryKeys[1] : $primaryKeys[0]; $where .= " \nAND link_t.`" . $params['linkModelLocalField'] . "` = " . intval($params['linkModelLocalPk']) . " "; } if (!empty($params['searchQuery'])) { $where .= " \nAND ("; if (empty($params['searchQueryFields'])) { $searchFields = $this->getFindSearchQueryParamFields('t', $joinCf); } else { $searchFields = $params['searchQueryFields']; } if (empty($searchFields)) { throw new \Exception("No automatic search fields defined for " . $this->className() . ". Maybe this model has no varchar fields? You can override function getFindSearchQueryParamFields() or you can supply them with FindParams::searchFields()"); } //`name` LIKE "test" OR `content` LIKE "test" $first = true; foreach ($searchFields as $searchField) { if ($first) { $first = false; } else { $where .= ' OR '; } $where .= $searchField . ' LIKE ' . $this->getDbConnection()->quote($params['searchQuery'], PDO::PARAM_STR); } if ($this->primaryKey() == 'id') { //Searc on exact ID match too. $idQuery = trim($params['searchQuery'], '% '); if (intval($idQuery) . "" === $idQuery) { if ($first) { $first = false; } else { $where .= ' OR '; } $where .= 't.id=' . intval($idQuery); } } $where .= ') '; } $group = ""; if ($this->aclField() && empty($params['ignoreAcl']) && (empty($params['limit']) || $params['limit'] != 1)) { //add group by pk so acl join won't return duplicate rows. Don't do this with limit=1 because that makes no sense and causes overhead. $pk = is_array($this->primaryKey()) ? $this->primaryKey() : array($this->primaryKey()); $group .= "\nGROUP BY t.`" . implode('`,t.`', $pk) . "` "; if (isset($params['group'])) { $group .= ", "; } } elseif (isset($params['group'])) { $group .= "\nGROUP BY "; } if (isset($params['group'])) { if (!is_array($params['group'])) { $params['group'] = array($params['group']); } for ($i = 0; $i < count($params['group']); $i++) { if ($i > 0) { $group .= ', '; } $group .= $this->_quoteColumnName($params['group'][$i]) . ' '; } } if (isset($params['having'])) { $group .= "\nHAVING " . $params['having']; } $order = ""; if (!empty($params['order'])) { $order .= "\nORDER BY "; if (!is_array($params['order'])) { $params['order'] = array($params['order']); } if (!isset($params['orderDirection'])) { $params['orderDirection'] = array('ASC'); } elseif (!is_array($params['orderDirection'])) { $params['orderDirection'] = array($params['orderDirection']); } for ($i = 0; $i < count($params['order']); $i++) { if ($i > 0) { $order .= ','; } $order .= $this->_quoteColumnName($params['order'][$i]) . ' '; if (isset($params['orderDirection'][$i])) { $order .= strtoupper($params['orderDirection'][$i]) == 'ASC' ? 'ASC ' : 'DESC '; } else { $order .= strtoupper($params['orderDirection'][0]) == 'ASC' ? 'ASC ' : 'DESC '; } } } $limit = ""; if (!empty($params['limit'])) { if (!isset($params['start'])) { $params['start'] = 0; } $limit .= "\nLIMIT " . intval($params['start']) . ',' . intval($params['limit']); } $sql = $select . $fields . $from . $joins . $where . $group . $order . $limit; if ($this->_debugSql) { $this->_debugSql($params, $sql); } try { if ($this->_debugSql) { $start = \GO\Base\Util\Date::getmicrotime(); } $result = $this->getDbConnection()->prepare($sql); if (isset($params['criteriaObject'])) { $criteriaObjectParams = $params['criteriaObject']->getParams(); foreach ($criteriaObjectParams as $param => $value) { $result->bindValue($param, $value[0], $value[1]); } $result->execute(); } elseif (isset($params['bindParams'])) { $result = $this->getDbConnection()->prepare($sql); $result->execute($params['bindParams']); } else { $result = $this->getDbConnection()->query($sql); } if ($this->_debugSql) { $end = \GO\Base\Util\Date::getmicrotime(); GO::debug("SQL Query took: " . ($end - $start)); } } catch (\Exception $e) { $msg = $e->getMessage(); if (GO::config()->debug) { $msg .= "\n\nFull SQL Query: " . $sql; if (isset($params['bindParams'])) { $msg .= "\nBind params: " . var_export($params['bindParams'], true); } if (isset($criteriaObjectParams)) { $msg .= "\nBind params: " . var_export($criteriaObjectParams, true); } $msg .= "\n\n" . $e->getTraceAsString(); GO::debug($msg); } //SQLSTATE[42S22]: Column not found: 1054 Unknown column 'progress' in 'order clause if (strpos($msg, 'order clause') !== false && strpos($msg, 'Unknown column') !== false) { $msg = GO::t('sortOrderError'); } throw new \Exception($msg); } $AS = new ActiveStatement($result, $this); if (!empty($params['calcFoundRows'])) { if (!empty($params['limit'])) { //Total numbers are cached in session when browsing through pages. if ($calcFoundRows) { if ($this->useSqlCalcFoundRows) { // //TODO: This is MySQL only code $sql = "SELECT FOUND_ROWS() as found;"; $r2 = $this->getDbConnection()->query($sql); $record = $r2->fetch(PDO::FETCH_ASSOC); //$foundRows = intval($record['found']); $foundRows = GO::session()->values[$queryUid] = intval($record['found']); } else { $countField = is_array($this->primaryKey()) ? '*' : 't.' . $this->primaryKey(); $sql = $select . 'COUNT(' . $countField . ') AS found ' . $from . $joins . $where; // GO::debug($sql); if ($this->_debugSql) { $this->_debugSql($params, $sql); $start = \GO\Base\Util\Date::getmicrotime(); } $r2 = $this->getDbConnection()->prepare($sql); if (isset($params['criteriaObject'])) { $criteriaObjectParams = $params['criteriaObject']->getParams(); foreach ($criteriaObjectParams as $param => $value) { $r2->bindValue($param, $value[0], $value[1]); } $r2->execute(); } elseif (isset($params['bindParams'])) { $r2 = $this->getDbConnection()->prepare($sql); $r2->execute($params['bindParams']); } else { $r2 = $this->getDbConnection()->query($sql); } if ($this->_debugSql) { $end = \GO\Base\Util\Date::getmicrotime(); GO::debug("SQL Count Query took: " . ($end - $start)); } $record = $r2->fetch(PDO::FETCH_ASSOC); //$foundRows = intval($record['found']); $foundRows = GO::session()->values[$queryUid] = intval($record['found']); } } else { $foundRows = GO::session()->values[$queryUid]; } $AS->foundRows = $foundRows; } } // //$result->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, $this->className()); // if($fetchObject) // $result->setFetchMode(PDO::FETCH_CLASS, $this->className(),array(false)); // else // $result->setFetchMode (PDO::FETCH_ASSOC); //TODO these values should be set on findByPk too. $AS->findParams = $params; if (isset($params['relation'])) { $AS->relation = $params['relation']; } if (!empty($params['fetchClass'])) { $AS->stmt->setFetchMode(PDO::FETCH_CLASS, $params['fetchClass']); } return $AS; }
public static function debugPageLoadTime($id) { $time = \GO\Base\Util\Date::getmicrotime() - self::$_scriptStartTime; \GO::debug("Script running at [{$id}] for " . $time . "ms"); }