mirror of
				https://github.com/Icinga/icingaweb2.git
				synced 2025-10-31 03:14:31 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			635 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			635 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
 | |
| 
 | |
| namespace Icinga\Data\Db;
 | |
| 
 | |
| use DateTime;
 | |
| use DateTimeZone;
 | |
| use Exception;
 | |
| use Icinga\Data\Inspectable;
 | |
| use Icinga\Data\Inspection;
 | |
| use PDO;
 | |
| use Iterator;
 | |
| use Zend_Db;
 | |
| use Zend_Db_Expr;
 | |
| use Icinga\Data\ConfigObject;
 | |
| use Icinga\Data\Extensible;
 | |
| use Icinga\Data\Filter\Filter;
 | |
| use Icinga\Data\Filter\FilterAnd;
 | |
| use Icinga\Data\Filter\FilterNot;
 | |
| use Icinga\Data\Filter\FilterOr;
 | |
| use Icinga\Data\Reducible;
 | |
| use Icinga\Data\ResourceFactory;
 | |
| use Icinga\Data\Selectable;
 | |
| use Icinga\Data\Updatable;
 | |
| use Icinga\Exception\ConfigurationError;
 | |
| use Icinga\Exception\ProgrammingError;
 | |
| 
 | |
| /**
 | |
|  * Encapsulate database connections and query creation
 | |
|  */
 | |
| class DbConnection implements Selectable, Extensible, Updatable, Reducible, Inspectable
 | |
| {
 | |
|     /**
 | |
|      * Connection config
 | |
|      *
 | |
|      * @var ConfigObject
 | |
|      */
 | |
|     private $config;
 | |
| 
 | |
|     /**
 | |
|      * Database type
 | |
|      *
 | |
|      * @var string
 | |
|      */
 | |
|     private $dbType;
 | |
| 
 | |
|     /**
 | |
|      * @var \Zend_Db_Adapter_Abstract
 | |
|      */
 | |
|     private $dbAdapter;
 | |
| 
 | |
|     /**
 | |
|      * Table prefix
 | |
|      *
 | |
|      * @var string
 | |
|      */
 | |
|     private $tablePrefix = '';
 | |
| 
 | |
|     private static $genericAdapterOptions = array(
 | |
|         Zend_Db::AUTO_QUOTE_IDENTIFIERS => false,
 | |
|         Zend_Db::CASE_FOLDING           => Zend_Db::CASE_LOWER
 | |
|     );
 | |
| 
 | |
|     private static $driverOptions = array(
 | |
|         PDO::ATTR_TIMEOUT    => 10,
 | |
|         PDO::ATTR_CASE       => PDO::CASE_LOWER,
 | |
|         PDO::ATTR_ERRMODE    => PDO::ERRMODE_EXCEPTION
 | |
|     );
 | |
| 
 | |
|     /**
 | |
|      * Create a new connection object
 | |
|      *
 | |
|      * @param ConfigObject $config
 | |
|      */
 | |
|     public function __construct(ConfigObject $config = null)
 | |
|     {
 | |
|         $this->config = $config;
 | |
|         $this->connect();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Provide a query on this connection
 | |
|      *
 | |
|      * @return  DbQuery
 | |
|      */
 | |
|     public function select()
 | |
|     {
 | |
|         return new DbQuery($this);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Fetch and return all rows of the given query's result set using an iterator
 | |
|      *
 | |
|      * @param   DbQuery     $query
 | |
|      *
 | |
|      * @return  Iterator
 | |
|      */
 | |
|     public function query(DbQuery $query)
 | |
|     {
 | |
|         return $query->getSelectQuery()->query();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get the connection configuration
 | |
|      *
 | |
|      * @return  ConfigObject
 | |
|      */
 | |
|     public function getConfig()
 | |
|     {
 | |
|         return $this->config;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Getter for database type
 | |
|      *
 | |
|      * @return string
 | |
|      */
 | |
|     public function getDbType()
 | |
|     {
 | |
|         return $this->dbType;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Getter for the Zend_Db_Adapter
 | |
|      *
 | |
|      * @return \Zend_Db_Adapter_Abstract
 | |
|      */
 | |
|     public function getDbAdapter()
 | |
|     {
 | |
|         return $this->dbAdapter;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Create a new connection
 | |
|      */
 | |
|     private function connect()
 | |
|     {
 | |
|         $genericAdapterOptions  = self::$genericAdapterOptions;
 | |
|         $driverOptions          = self::$driverOptions;
 | |
|         $adapterParamaters      = array(
 | |
|             'host'              => $this->config->host,
 | |
|             'username'          => $this->config->username,
 | |
|             'password'          => $this->config->password,
 | |
|             'dbname'            => $this->config->dbname,
 | |
|             'charset'           => $this->config->charset ?: null,
 | |
|             'options'           => & $genericAdapterOptions,
 | |
|             'driver_options'    => & $driverOptions
 | |
|         );
 | |
|         $this->dbType = strtolower($this->config->get('db', 'mysql'));
 | |
|         switch ($this->dbType) {
 | |
|             case 'mssql':
 | |
|                 $adapter = 'Pdo_Mssql';
 | |
|                 $pdoType = $this->config->get('pdoType');
 | |
|                 if (empty($pdoType)) {
 | |
|                     if (extension_loaded('sqlsrv')) {
 | |
|                         $adapter = 'Sqlsrv';
 | |
|                     } else {
 | |
|                         $pdoType = 'dblib';
 | |
|                     }
 | |
|                 }
 | |
|                 if ($pdoType === 'dblib') {
 | |
|                     // Driver does not support setting attributes
 | |
|                     unset($adapterParamaters['options']);
 | |
|                     unset($adapterParamaters['driver_options']);
 | |
|                 }
 | |
|                 if (! empty($pdoType)) {
 | |
|                     $adapterParamaters['pdoType'] = $pdoType;
 | |
|                 }
 | |
|                 $defaultPort = 1433;
 | |
|                 break;
 | |
|             case 'mysql':
 | |
|                 $adapter = 'Pdo_Mysql';
 | |
|                 if ($this->config->use_ssl) {
 | |
|                     # The presence of these keys as empty strings or null cause non-ssl connections to fail
 | |
|                     if ($this->config->ssl_key) {
 | |
|                         $adapterParamaters['driver_options'][PDO::MYSQL_ATTR_SSL_KEY] = $this->config->ssl_key;
 | |
|                     }
 | |
|                     if ($this->config->ssl_cert) {
 | |
|                         $adapterParamaters['driver_options'][PDO::MYSQL_ATTR_SSL_CERT] = $this->config->ssl_cert;
 | |
|                     }
 | |
|                     if ($this->config->ssl_ca) {
 | |
|                         $adapterParamaters['driver_options'][PDO::MYSQL_ATTR_SSL_CA] = $this->config->ssl_ca;
 | |
|                     }
 | |
|                     if ($this->config->ssl_capath) {
 | |
|                         $adapterParamaters['driver_options'][PDO::MYSQL_ATTR_SSL_CAPATH] = $this->config->ssl_capath;
 | |
|                     }
 | |
|                     if ($this->config->ssl_cipher) {
 | |
|                         $adapterParamaters['driver_options'][PDO::MYSQL_ATTR_SSL_CIPHER] = $this->config->ssl_cipher;
 | |
|                     }
 | |
|                     if (defined('PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT')
 | |
|                         && $this->config->ssl_do_not_verify_server_cert
 | |
|                     ) {
 | |
|                         $adapterParamaters['driver_options'][PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = false;
 | |
|                     }
 | |
|                 }
 | |
|                 /*
 | |
|                  * Set MySQL server SQL modes to behave as closely as possible to Oracle and PostgreSQL. Note that the
 | |
|                  * ONLY_FULL_GROUP_BY mode is left on purpose because MySQL requires you to specify all non-aggregate
 | |
|                  * columns in the group by list even if the query is grouped by the master table's primary key which is
 | |
|                  * valid ANSI SQL though. Further in that case the query plan would suffer if you add more columns to
 | |
|                  * the group by list.
 | |
|                  */
 | |
|                 $driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] =
 | |
|                     'SET SESSION SQL_MODE=\'STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,'
 | |
|                     . 'ANSI_QUOTES,PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION\'';
 | |
|                 if (isset($adapterParamaters['charset'])) {
 | |
|                     $driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] .= ', NAMES ' . $adapterParamaters['charset'];
 | |
|                     if (trim($adapterParamaters['charset']) === 'latin1') {
 | |
|                         // Required for MySQL 8+ because we need PIPES_AS_CONCAT and
 | |
|                         // have several columns with explicit COLLATE instructions
 | |
|                         $driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] .= ' COLLATE latin1_general_ci';
 | |
|                     }
 | |
| 
 | |
|                     unset($adapterParamaters['charset']);
 | |
|                 }
 | |
| 
 | |
|                 $driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] .= ", time_zone='" . $this->defaultTimezoneOffset() . "'";
 | |
|                 $driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] .=';';
 | |
|                 $defaultPort = 3306;
 | |
|                 break;
 | |
|             case 'oci':
 | |
|                 $adapter = 'Oracle';
 | |
|                 unset($adapterParamaters['options']);
 | |
|                 unset($adapterParamaters['driver_options']);
 | |
|                 $adapterParamaters['driver_options'] = array(
 | |
|                     'lob_as_string' => true
 | |
|                 );
 | |
|                 $defaultPort = 1521;
 | |
|                 break;
 | |
|             case 'oracle':
 | |
|                 $adapter = 'Pdo_Oci';
 | |
|                 $defaultPort = 1521;
 | |
| 
 | |
|                 // remove host parameter when not configured
 | |
|                 if (empty($this->config->host)) {
 | |
|                     unset($adapterParamaters['host']);
 | |
|                 }
 | |
|                 break;
 | |
|             case 'pgsql':
 | |
|                 $adapter = 'Pdo_Pgsql';
 | |
|                 $defaultPort = 5432;
 | |
|                 break;
 | |
|             case 'ibm':
 | |
|                 $adapter = 'Pdo_Ibm';
 | |
|                 $defaultPort = 50000;
 | |
|                 break;
 | |
|             case 'sqlite':
 | |
|                 $adapter = 'Pdo_Sqlite';
 | |
|                 $defaultPort = 0; // Dummy port because a value is required
 | |
|                 break;
 | |
|             default:
 | |
|                 throw new ConfigurationError(
 | |
|                     'Backend "%s" is not supported',
 | |
|                     $this->dbType
 | |
|                 );
 | |
|         }
 | |
|         $adapterParamaters['port'] = $this->config->get('port', $defaultPort);
 | |
|         $this->dbAdapter = Zend_Db::factory($adapter, $adapterParamaters);
 | |
|         $this->dbAdapter->setFetchMode(Zend_Db::FETCH_OBJ);
 | |
|         // TODO(el/tg): The profiler is disabled per default, why do we disable the profiler explicitly?
 | |
|         $this->dbAdapter->getProfiler()->setEnabled(false);
 | |
|     }
 | |
| 
 | |
|     public static function fromResourceName($name)
 | |
|     {
 | |
|         return new static(ResourceFactory::getResourceConfig($name));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @deprecated Use Connection::getDbAdapter() instead
 | |
|      */
 | |
|     public function getConnection()
 | |
|     {
 | |
|         return $this->dbAdapter;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Getter for the table prefix
 | |
|      *
 | |
|      * @return string
 | |
|      */
 | |
|     public function getTablePrefix()
 | |
|     {
 | |
|         return $this->tablePrefix;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Setter for the table prefix
 | |
|      *
 | |
|      * @param   string $prefix
 | |
|      *
 | |
|      * @return  $this
 | |
|      */
 | |
|     public function setTablePrefix($prefix)
 | |
|     {
 | |
|         $this->tablePrefix = $prefix;
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get offset from the current default timezone to GMT
 | |
|      *
 | |
|      * @return string
 | |
|      */
 | |
|     protected function defaultTimezoneOffset()
 | |
|     {
 | |
|         $tz = new DateTimeZone(date_default_timezone_get());
 | |
|         $offset = $tz->getOffset(new DateTime());
 | |
|         $prefix = $offset >= 0 ? '+' : '-';
 | |
|         $offset = abs($offset);
 | |
|         $hours = (int) floor($offset / 3600);
 | |
|         $minutes = (int) floor(($offset % 3600) / 60);
 | |
|         return sprintf('%s%d:%02d', $prefix, $hours, $minutes);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Count all rows of the result set
 | |
|      *
 | |
|      * @param   DbQuery     $query
 | |
|      *
 | |
|      * @return  int
 | |
|      */
 | |
|     public function count(DbQuery $query)
 | |
|     {
 | |
|         return (int) $this->dbAdapter->fetchOne($query->getCountQuery());
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Retrieve an array containing all rows of the result set
 | |
|      *
 | |
|      * @param   DbQuery $query
 | |
|      *
 | |
|      * @return  array
 | |
|      */
 | |
|     public function fetchAll(DbQuery $query)
 | |
|     {
 | |
|         return $this->dbAdapter->fetchAll($query->getSelectQuery());
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Fetch the first row of the result set
 | |
|      *
 | |
|      * @param   DbQuery $query
 | |
|      *
 | |
|      * @return  mixed
 | |
|      */
 | |
|     public function fetchRow(DbQuery $query)
 | |
|     {
 | |
|         return $this->dbAdapter->fetchRow($query->getSelectQuery());
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Fetch the first column of all rows of the result set as an array
 | |
|      *
 | |
|      * @param   DbQuery   $query
 | |
|      *
 | |
|      * @return  array
 | |
|      */
 | |
|     public function fetchColumn(DbQuery $query)
 | |
|     {
 | |
|         return $this->dbAdapter->fetchCol($query->getSelectQuery());
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Fetch the first column of the first row of the result set
 | |
|      *
 | |
|      * @param   DbQuery $query
 | |
|      *
 | |
|      * @return  string
 | |
|      */
 | |
|     public function fetchOne(DbQuery $query)
 | |
|     {
 | |
|         return $this->dbAdapter->fetchOne($query->getSelectQuery());
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Fetch all rows of the result set as an array of key-value pairs
 | |
|      *
 | |
|      * The first column is the key, the second column is the value.
 | |
|      *
 | |
|      * @param   DbQuery $query
 | |
|      *
 | |
|      * @return  array
 | |
|      */
 | |
|     public function fetchPairs(DbQuery $query)
 | |
|     {
 | |
|         return $this->dbAdapter->fetchPairs($query->getSelectQuery());
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Insert a table row with the given data
 | |
|      *
 | |
|      * Note that the base implementation does not perform any quoting on the $table argument.
 | |
|      * Pass an array with a column name (the same as in $bind) and a PDO::PARAM_* constant as value
 | |
|      * as third parameter $types to define a different type than string for a particular column.
 | |
|      *
 | |
|      * @param   string  $table
 | |
|      * @param   array   $bind
 | |
|      * @param   array   $types
 | |
|      *
 | |
|      * @return  int             The number of affected rows
 | |
|      */
 | |
|     public function insert($table, array $bind, array $types = array())
 | |
|     {
 | |
|         $columns = $values = array();
 | |
|         foreach ($bind as $column => $value) {
 | |
|             $columns[] = $column;
 | |
|             if ($value instanceof Zend_Db_Expr) {
 | |
|                 $values[] = (string) $value;
 | |
|                 unset($bind[$column]);
 | |
|             } else {
 | |
|                 $values[] = ':' . $column;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         $sql = 'INSERT INTO ' . $table
 | |
|             . ' (' . join(', ', $columns) . ') '
 | |
|             . 'VALUES (' . join(', ', $values) . ')';
 | |
|         $statement = $this->dbAdapter->prepare($sql);
 | |
| 
 | |
|         foreach ($bind as $column => $value) {
 | |
|             $type = isset($types[$column]) ? $types[$column] : PDO::PARAM_STR;
 | |
|             $statement->bindValue(':' . $column, $value, $type);
 | |
|         }
 | |
| 
 | |
|         $statement->execute();
 | |
|         return $statement->rowCount();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Update table rows with the given data, optionally limited by using a filter
 | |
|      *
 | |
|      * Note that the base implementation does not perform any quoting on the $table argument.
 | |
|      * Pass an array with a column name (the same as in $bind) and a PDO::PARAM_* constant as value
 | |
|      * as fourth parameter $types to define a different type than string for a particular column.
 | |
|      *
 | |
|      * @param   string  $table
 | |
|      * @param   array   $bind
 | |
|      * @param   Filter  $filter
 | |
|      * @param   array   $types
 | |
|      *
 | |
|      * @return  int             The number of affected rows
 | |
|      */
 | |
|     public function update($table, array $bind, Filter $filter = null, array $types = array())
 | |
|     {
 | |
|         $set = array();
 | |
|         foreach ($bind as $column => $value) {
 | |
|             if ($value instanceof Zend_Db_Expr) {
 | |
|                 $set[] = $column . ' = ' . $value;
 | |
|                 unset($bind[$column]);
 | |
|             } else {
 | |
|                 $set[] = $column . ' = :' . $column;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         $sql = 'UPDATE ' . $table
 | |
|             . ' SET ' . join(', ', $set)
 | |
|             . ($filter ? ' WHERE ' . $this->renderFilter($filter) : '');
 | |
|         $statement = $this->dbAdapter->prepare($sql);
 | |
| 
 | |
|         foreach ($bind as $column => $value) {
 | |
|             $type = isset($types[$column]) ? $types[$column] : PDO::PARAM_STR;
 | |
|             $statement->bindValue(':' . $column, $value, $type);
 | |
|         }
 | |
| 
 | |
|         $statement->execute();
 | |
|         return $statement->rowCount();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Delete table rows, optionally limited by using a filter
 | |
|      *
 | |
|      * @param   string  $table
 | |
|      * @param   Filter  $filter
 | |
|      *
 | |
|      * @return  int             The number of affected rows
 | |
|      */
 | |
|     public function delete($table, Filter $filter = null)
 | |
|     {
 | |
|         return $this->dbAdapter->delete($table, $filter ? $this->renderFilter($filter) : '');
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Render and return the given filter as SQL-WHERE clause
 | |
|      *
 | |
|      * @param   Filter  $filter
 | |
|      *
 | |
|      * @return  string
 | |
|      */
 | |
|     public function renderFilter(Filter $filter, $level = 0)
 | |
|     {
 | |
|         // TODO: This is supposed to supersede DbQuery::renderFilter()
 | |
|         $where = '';
 | |
|         if ($filter->isChain()) {
 | |
|             if ($filter instanceof FilterAnd) {
 | |
|                 $operator = ' AND ';
 | |
|             } elseif ($filter instanceof FilterOr) {
 | |
|                 $operator = ' OR ';
 | |
|             } elseif ($filter instanceof FilterNot) {
 | |
|                 $operator = ' AND ';
 | |
|                 $where .= ' NOT ';
 | |
|             } else {
 | |
|                 throw new ProgrammingError('Cannot render filter: %s', get_class($filter));
 | |
|             }
 | |
| 
 | |
|             if (! $filter->isEmpty()) {
 | |
|                 $parts = array();
 | |
|                 foreach ($filter->filters() as $filterPart) {
 | |
|                     $part = $this->renderFilter($filterPart, $level + 1);
 | |
|                     if ($part) {
 | |
|                         $parts[] = $part;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (! empty($parts)) {
 | |
|                     if ($level > 0) {
 | |
|                         $where .= ' (' . implode($operator, $parts) . ') ';
 | |
|                     } else {
 | |
|                         $where .= implode($operator, $parts);
 | |
|                     }
 | |
|                 }
 | |
|             } else {
 | |
|                 return ''; // Explicitly return the empty string due to the FilterNot case
 | |
|             }
 | |
|         } else {
 | |
|             $where .= $this->renderFilterExpression($filter);
 | |
|         }
 | |
| 
 | |
|         return $where;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Render and return the given filter expression
 | |
|      *
 | |
|      * @param   Filter  $filter
 | |
|      *
 | |
|      * @return  string
 | |
|      */
 | |
|     protected function renderFilterExpression(Filter $filter)
 | |
|     {
 | |
|         $column = $filter->getColumn();
 | |
|         $sign = $filter->getSign();
 | |
|         $value = $filter->getExpression();
 | |
| 
 | |
|         if (is_array($value)) {
 | |
|             if ($sign === '=') {
 | |
|                 return $column . ' IN (' . $this->dbAdapter->quote($value) . ')';
 | |
|             } elseif ($sign === '!=') {
 | |
|                 return sprintf('(%1$s NOT IN (%2$s) OR %1$s IS NULL)', $column, $this->dbAdapter->quote($value));
 | |
|             }
 | |
| 
 | |
|             throw new ProgrammingError(
 | |
|                 'Unable to render array expressions with operators other than equal or not equal'
 | |
|             );
 | |
|         } elseif ($sign === '=' && strpos($value, '*') !== false) {
 | |
|             if ($value === '*') {
 | |
|                 // We'll ignore such filters as it prevents index usage and because "*" means anything, so whether we're
 | |
|                 // using a real column with a valid comparison here or just an expression which can only be evaluated to
 | |
|                 // true makes no difference, except for performance reasons...
 | |
|                 return new Zend_Db_Expr('TRUE');
 | |
|             }
 | |
| 
 | |
|             return $column . ' LIKE ' . $this->dbAdapter->quote(preg_replace('~\*~', '%', $value));
 | |
|         } elseif ($sign === '!=' && strpos($value, '*') !== false) {
 | |
|             if ($value === '*') {
 | |
|                 // We'll ignore such filters as it prevents index usage and because "*" means nothing, so whether we're
 | |
|                 // using a real column with a valid comparison here or just an expression which cannot be evaluated to
 | |
|                 // true makes no difference, except for performance reasons...
 | |
|                 return new Zend_Db_Expr('FALSE');
 | |
|             }
 | |
| 
 | |
|             return sprintf(
 | |
|                 '(%1$s NOT LIKE %2$s OR %1$s IS NULL)',
 | |
|                 $column,
 | |
|                 $this->dbAdapter->quote(preg_replace('~\*~', '%', $value))
 | |
|             );
 | |
|         } elseif ($sign === '!=') {
 | |
|             return sprintf('(%1$s != %2$s OR %1$s IS NULL)', $column, $this->dbAdapter->quote($value));
 | |
|         } else {
 | |
|             return sprintf('%s %s %s', $column, $sign, $this->dbAdapter->quote($value));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public function inspect()
 | |
|     {
 | |
|         $insp = new Inspection('Db Connection');
 | |
|         try {
 | |
|             $this->getDbAdapter()->getConnection();
 | |
|             $config = $this->dbAdapter->getConfig();
 | |
|             $insp->write(sprintf(
 | |
|                 'Connection to %s as %s on %s:%s successful',
 | |
|                 $config['dbname'],
 | |
|                 $config['username'],
 | |
|                 array_key_exists('host', $config) ? $config['host'] : '(none)',
 | |
|                 $config['port']
 | |
|             ));
 | |
|             switch ($this->dbType) {
 | |
|                 case 'mysql':
 | |
|                     $rows = $this->dbAdapter->query(
 | |
|                         'SHOW VARIABLES WHERE variable_name ' .
 | |
|                         'IN (\'version\', \'protocol_version\', \'version_compile_os\', \'have_ssl\');'
 | |
|                     )->fetchAll();
 | |
|                     $sqlinsp = new Inspection('MySQL');
 | |
|                     $hasSsl = false;
 | |
|                     foreach ($rows as $row) {
 | |
|                         $sqlinsp->write($row->variable_name . ': ' . $row->value);
 | |
|                         if ($row->variable_name === 'have_ssl' && $row->value === 'YES') {
 | |
|                             $hasSsl = true;
 | |
|                         }
 | |
|                     }
 | |
|                     if ($hasSsl) {
 | |
|                         $ssl_rows = $this->dbAdapter->query(
 | |
|                             'SHOW STATUS WHERE variable_name ' .
 | |
|                             'IN (\'Ssl_Cipher\');'
 | |
|                         )->fetchAll();
 | |
|                         foreach ($ssl_rows as $ssl_row) {
 | |
|                             $sqlinsp->write($ssl_row->variable_name . ': ' . $ssl_row->value);
 | |
|                         }
 | |
|                     }
 | |
|                     $insp->write($sqlinsp);
 | |
|                     break;
 | |
|                 case 'pgsql':
 | |
|                     $row = $this->dbAdapter->query('SELECT version();')->fetchAll();
 | |
|                     $sqlinsp = new Inspection('PostgreSQL');
 | |
|                     $sqlinsp->write($row[0]->version);
 | |
|                     $insp->write($sqlinsp);
 | |
|                     break;
 | |
|             }
 | |
|         } catch (Exception $e) {
 | |
|             return $insp->error(sprintf('Connection failed %s', $e->getMessage()));
 | |
|         }
 | |
|         return $insp;
 | |
|     }
 | |
| }
 |