Joywork/engine/classes/MysqlPdo.php

204 lines
6.6 KiB
PHP
Raw Normal View History

2026-05-22 20:21:54 +02:00
<?php
/**
* Класс для работы с базой mysql по средствам PDO
*/
Class MysqlPdo{
private static $instance;
private $pdo;
private $opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
private $host;
private $port = '3306';
private $db;
private $user;
private $pass;
private $charset = 'utf8';
private $sphinx = false;
private $PostgreSQL = false;
public function __construct($host, $db, $user, $pass, $sphinx = false, $port = null, $PostgreSQL=false, $opt = array(), $charset = null){
$this->host = $host;
$this->db = $db;
$this->user = $user;
$this->pass = $pass;
if(!empty($opt)) {
$this->opt = $opt;
}
if($charset){
$this->charset = $charset;
}
if($sphinx){
$this->sphinx = $sphinx;
}
if($PostgreSQL){
$this->PostgreSQL = $PostgreSQL;
}
if($port){
$this->port = $port;
}
$this->pdo = $this->connect();
self::$instance = $this;
}
// Кэш недоступности PG-хостов в рамках одного PHP-запроса.
// Чтобы не делать fsockopen-чек повторно для одного и того же хоста (экономит 2 сек на каждом повторе).
private static $pg_unreachable_cache = array();
//Подключение
private function connect(){
$dsn = "mysql:host=".$this->host.";port=".$this->port.";dbname=".$this->db;
if($this->sphinx){
$dsn = "mysql:host=".$this->host.";port=".$this->port;
} else if ($this->PostgreSQL){
$dsn = "pgsql:host=".$this->host.";port=".$this->port;
// Быстрая проверка доступности PG-хоста (2 сек таймаут).
// Без этой проверки PDO-connect может висеть 30-60 секунд при недоступном хосте,
// что валит весь кабинет на окружениях без PG (например, dev).
// На проде PG доступен — проверка мгновенна. На dev — 2 сек на первый раз, потом 0 сек.
$cacheKey = $this->host . ':' . $this->port;
if (isset(self::$pg_unreachable_cache[$cacheKey])) {
// Не логируем — про этот хост в текущем запросе уже отписались.
throw new RuntimeException(self::$pg_unreachable_cache[$cacheKey]);
}
$sock = @fsockopen($this->host, (int)$this->port, $errno, $errstr, 2);
if (!$sock) {
$msg = "PostgreSQL unreachable at {$this->host}:{$this->port} ({$errno}: {$errstr})";
self::$pg_unreachable_cache[$cacheKey] = $msg;
// Пишем ОДИН раз в php error_log при первом обнаружении недоступности в текущем запросе.
// На проде это видно в стандартном error_log сервера и поможет быстро поймать момент отказа PG.
$reqUri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : 'cli';
@error_log("[MysqlPdo] {$msg} | request: {$reqUri}");
throw new RuntimeException($msg);
}
fclose($sock);
}
try {
$pdo = null;
if($this->sphinx){
$pdo = new PDO($dsn);
} else {
$pdo = new PDO($dsn, $this->user, $this->pass, $this->opt);
}
return $pdo;
} catch (PDOException $e) {
// Для MySQL/Sphinx без БД приложение работать не может — die как и было.
// Для PG нас сюда не должны пускать (fsockopen-check выше уже отсёк),
// но на всякий случай — бросаем исключение, не die.
if ($this->PostgreSQL) {
throw new RuntimeException('PostgreSQL connection failed: ' . $e->getMessage());
}
die('Ooooops что-то пошло не так. Мы уже работаем над проблемой.');
}
}
//mysql_query
public function query($query, $error = false){
$stmt = null;
try{
$stmt = $this->pdo->query($query);
} catch (Exception $e){
print_r($query);
print_r($e->getMessage());
}
if(!$stmt && $error){
print_r($query);
print_r($this->pdo->errorInfo());
}
return $stmt;
}
//mysql_query with named params
public function queryNamed($query, $params){
$statement = $this->pdo->prepare($query);
$statement->execute($params);
return $statement;
}
//mysql_fetch_assoc
public function fetch_assoc($stmt){
if (!$stmt || !($stmt instanceof PDOStatement)) {
return null;
}
$row = $stmt->fetch(PDO::FETCH_ASSOC);
return $row;
}
//mysql_num_rows
public function num_rows($stmt){
if (!$stmt || !($stmt instanceof PDOStatement)) {
return 0;
}
$rows = $stmt->rowCount();
return $rows;
}
//mysql_result
public function result_pdo($stmt){
if (!$stmt || !($stmt instanceof PDOStatement)) {
return [];
}
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $res;
}
public function result($stmt, $column = 0){
if (!$stmt || !($stmt instanceof PDOStatement)) {
return null;
}
$res = $stmt->fetchColumn($column);
return $res;
}
//mysql_fetch_row
function fetch_row($stmt){
if (!$stmt || !($stmt instanceof PDOStatement)) {
return null;
}
$row = $stmt->fetch(PDO::FETCH_NUM);
return $row;
}
//mysql_insert_id
function insert_id(){
$id = $this->pdo->lastInsertId();
return $id;
}
//mysql_error
function error(){
return $this->pdo->errorInfo();
}
//mysql_error
function quote($str){
return $this->pdo->quote($str);
}
static function get() {
return self::$instance;
}
public function errorInfo() {
return $this->pdo->errorInfo();
}
}