diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6817ae50..32b65368 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: '8.0' - extensions: mbstring, gd, gettext, fileinfo, pdo, pdo_mysql, mysqli, zip + extensions: mbstring, gd, gettext, fileinfo, pdo, pdo_mysql, zip - uses: actions/checkout@v2 diff --git a/app/locale/en_US.UTF-8/LC_MESSAGES/messages.mo b/app/locale/en_US.UTF-8/LC_MESSAGES/messages.mo index e5366313..b0f49446 100644 Binary files a/app/locale/en_US.UTF-8/LC_MESSAGES/messages.mo and b/app/locale/en_US.UTF-8/LC_MESSAGES/messages.mo differ diff --git a/app/locale/en_US.UTF-8/LC_MESSAGES/messages.po b/app/locale/en_US.UTF-8/LC_MESSAGES/messages.po index 729be3e5..b8608bfe 100644 --- a/app/locale/en_US.UTF-8/LC_MESSAGES/messages.po +++ b/app/locale/en_US.UTF-8/LC_MESSAGES/messages.po @@ -1119,7 +1119,7 @@ msgid "Check connection library with MySQL" msgstr "" #: shell/../view/admin/common/install.html:78 -msgid "Please enable pdo or mysqli" +msgid "Please enable pdo" msgstr "" #: shell/../view/admin/common/install.html:94 @@ -2498,8 +2498,8 @@ msgstr "" msgid "The page you are looking for does not exist." msgstr "" -msgid "Execute `Create database` failed. Please `Create database` your self." -msgstr "" +msgid "Please set correct the DB connection settings." +msgstr "DBの接続設定をご確認ください。" msgid "(If not exists, will be try create)" msgstr "" diff --git a/app/locale/ja_JP.UTF-8/LC_MESSAGES/messages.mo b/app/locale/ja_JP.UTF-8/LC_MESSAGES/messages.mo index 1e520239..ae28c7e2 100644 Binary files a/app/locale/ja_JP.UTF-8/LC_MESSAGES/messages.mo and b/app/locale/ja_JP.UTF-8/LC_MESSAGES/messages.mo differ diff --git a/app/locale/ja_JP.UTF-8/LC_MESSAGES/messages.po b/app/locale/ja_JP.UTF-8/LC_MESSAGES/messages.po index 7a5beb15..8386a47a 100644 --- a/app/locale/ja_JP.UTF-8/LC_MESSAGES/messages.po +++ b/app/locale/ja_JP.UTF-8/LC_MESSAGES/messages.po @@ -1109,8 +1109,8 @@ msgid "Check connection library with MySQL" msgstr "MySQLとの接続ライブラリチェック" #: shell/../view/admin/common/install.html:78 -msgid "Please enable pdo or mysqli" -msgstr "mysqli または pdoを有効にしてください" +msgid "Please enable pdo" +msgstr "pdoを有効にしてください" #: shell/../view/admin/common/install.html:94 msgid "Check connection to the MySQL" @@ -2545,8 +2545,8 @@ msgstr "ブログに設置されたプラグイン、またはテンプレート msgid "The page you are looking for does not exist." msgstr "お探しのページは存在しません" -msgid "Execute `Create database` failed. Please `Create database` your self." -msgstr "`CREATE DATABASE`のsql実行に失敗しました、事前に`CREATE DATABASE`を実行してください。" +msgid "Please set correct the DB connection settings." +msgstr "DBの接続設定をご確認ください。" msgid "(If not exists, will be try create)" msgstr "(未作成の場合、作成を試行します)" diff --git a/app/src/Model/BlogsModel.php b/app/src/Model/BlogsModel.php index bebbc22f..5534ef73 100644 --- a/app/src/Model/BlogsModel.php +++ b/app/src/Model/BlogsModel.php @@ -8,6 +8,7 @@ use Fc2blog\Web\Request; use InvalidArgumentException; use OutOfBoundsException; +use PDOException; class BlogsModel extends Model { @@ -71,6 +72,7 @@ public static function isPasswordRegistered($blog_id): bool * ディレクトリとして使用済みかどうか * @param string $value * @return bool|string + * @noinspection PhpUnused */ public static function usableDirectory(string $value) { @@ -233,29 +235,34 @@ public static function getTemplateIds($blog): array /** * ブログの一覧(SelectBox用) * @param $user_id - * @return mixed + * @return array */ - public function getSelectList($user_id) + public function getSelectList($user_id): array { - return $this->find('list', array( - 'fields' => array('id', 'name'), - 'where' => 'user_id=?', - 'params' => array($user_id), - 'order' => 'created_at DESC', - )); + try { + return $this->find('list', array( + 'fields' => array('id', 'name'), + 'where' => 'user_id=?', + 'params' => array($user_id), + 'order' => 'created_at DESC', + )); + } catch (PDOException $e) { + // インストール前や初期化前など、クエリが出来ないケースがある + return []; + } } /** * ブログIDをキーにユーザーIDを条件としてブログを取得 - * @param $blog_id + * @param $id * @param $user_id * @param array $options * @return mixed */ - public function findByIdAndUserId($blog_id, $user_id, array $options = []): array + public function findByIdAndUserId($id, $user_id, array $options = []): array { $options['where'] = isset($options['where']) ? 'id=? AND user_id=? AND ' . $options['where'] : 'id=? AND user_id=?'; - $options['params'] = isset($options['params']) ? array_merge(array($blog_id, $user_id), $options['params']) : array($blog_id, $user_id); + $options['params'] = isset($options['params']) ? array_merge(array($id, $user_id), $options['params']) : array($id, $user_id); return $this->find('row', $options); } @@ -263,9 +270,9 @@ public function findByIdAndUserId($blog_id, $user_id, array $options = []): arra * ユーザーIDをキーにしてブログを取得 * @param $user_id * @param array $options - * @return mixed + * @return array */ - public function findByUserId($user_id, $options = array()) + public function findByUserId($user_id, array $options = array()) { $options['where'] = isset($options['where']) ? 'user_id=? AND ' . $options['where'] : 'user_id=?'; $options['params'] = isset($options['params']) ? array_merge(array($user_id), $options['params']) : array($user_id); @@ -286,7 +293,7 @@ public function findByRandom() /** * ログイン後最初に表示するブログを取得する * @param $user - * @return mixed + * @return array */ public function getLoginBlog($user) { @@ -311,7 +318,7 @@ public function getLoginBlog($user) /** * ユーザーIDをキーにブログのリストを取得 * @param int $user_id - * @return mixed + * @return array */ public function getListByUserId(int $user_id) { @@ -349,7 +356,7 @@ public function insert(array $data, array $options = []) { // 主キーがauto_incrementじゃないのでreturn値の受け取り方を変更 $data['created_at'] = $data['updated_at'] = date('Y-m-d H:i:s'); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; if (!parent::insert($data, $options)) { return false; } @@ -496,7 +503,7 @@ public static function regeneratePluginPhpByBlogId(string $blog_id): void * @param array $values * @param $id * @param array $options - * @return array|false|int|mixed + * @return array|int */ public function updateById(array $values, $id, array $options = []) { @@ -507,7 +514,8 @@ public function updateById(array $values, $id, array $options = []) /** * 最終投稿日時更新 * @param $id - * @return array|false|int|mixed + * @return array|int + * @noinspection PhpUnused */ public function updateLastPostedAt($id) { @@ -519,7 +527,7 @@ public function updateLastPostedAt($id) * テンプレートの切り替え * @param array $blog_template * @param string $blog_id - * @return array|false|int|mixed + * @return array|int */ public function switchTemplate(array $blog_template, string $blog_id) { @@ -533,13 +541,12 @@ public function switchTemplate(array $blog_template, string $blog_id) $reply_type = strstr($blog_template['html'], '<%comment_reply_body>') ? Config::get('BLOG_TEMPLATE.COMMENT_TYPE.REPLY') : Config::get('BLOG_TEMPLATE.COMMENT_TYPE.AFTER'); // コメントの表示タイプを更新 - Model::load('BlogSettings')->updateReplyType($device_type, $reply_type, $blog_id); + (new BlogSettingsModel())->updateReplyType($device_type, $reply_type, $blog_id); $ret = $this->updateById($data, $blog_id); if ($ret) { // 更新に成功した場合 現在のテンプレートを削除 - Model::load('BlogTemplates'); $template_path = BlogTemplatesModel::getTemplateFilePath($blog_id, $device_type); is_file($template_path) && unlink($template_path); $css_path = BlogTemplatesModel::getCssFilePath($blog_id, $device_type); @@ -556,7 +563,7 @@ public function switchTemplate(array $blog_template, string $blog_id) * @param array $options * @return bool|int */ - public function deleteByIdAndUserId($blog_id, int $user_id, $options = array()) + public function deleteByIdAndUserId($blog_id, int $user_id, array $options = array()) { if (!parent::deleteById($blog_id, array('where' => 'user_id=?', 'params' => array($user_id)))) { return 0; @@ -635,6 +642,7 @@ static public function isCorrectHttpSchemaByBlog(Request $request, Blog $blog): * @param Request $request * @param string $blog_id * @return bool + * @noinspection PhpUnused */ static public function isCorrectHttpSchemaByBlogId(Request $request, string $blog_id): bool { @@ -762,6 +770,7 @@ static public function getDefaultBlogId(): ?string /** * @param Request $request * @return string|null + * @noinspection PhpUnused */ static public function getBlogIdByRequestOrDefault(Request $request): ?string { diff --git a/app/src/Model/CategoriesModel.php b/app/src/Model/CategoriesModel.php index 9b867355..c101b393 100644 --- a/app/src/Model/CategoriesModel.php +++ b/app/src/Model/CategoriesModel.php @@ -71,6 +71,7 @@ public function validate(array $data, ?array &$valid_data = [], array $white_lis * @param $data * @param $model * @return bool|string + * @noinspection PhpUnusedParameterInspection */ public static function uniqueName($value, $option, $key, $data, $model) { @@ -183,7 +184,7 @@ public function getEntryCategories($blog_id, $entry_id) SQL; $params = array($blog_id, $entry_id, $blog_id); $options = array(); - $options['result'] = DBInterface::RESULT_ALL; + $options['result'] = PDOQuery::RESULT_ALL; return $this->findSql($sql, $params, $options); } @@ -210,7 +211,7 @@ public function getEntriesCategories($blog_id, $entry_ids = array()) SQL; $params = array_merge(array($blog_id), $entry_ids, array($blog_id)); $options = array(); - $options['result'] = DBInterface::RESULT_ALL; + $options['result'] = PDOQuery::RESULT_ALL; $categories = $this->findSql($sql, $params, $options); $entries_categories = array(); @@ -253,7 +254,7 @@ public function increaseCount($blog_id, $ids = array()) } $sql = 'UPDATE ' . $this->getTableName() . ' SET count=count+1 WHERE blog_id=? AND id IN (' . implode(',', array_fill(0, count($ids), '?')) . ')'; $params = array_merge(array($blog_id), $ids); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } @@ -270,7 +271,7 @@ public function decreaseCount($blog_id, $ids = array()) } $sql = 'UPDATE ' . $this->getTableName() . ' SET count=count-1 WHERE blog_id=? AND count>0 AND id IN (' . implode(',', array_fill(0, count($ids), '?')) . ')'; $params = array_merge(array($blog_id), $ids); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } diff --git a/app/src/Model/CommentsModel.php b/app/src/Model/CommentsModel.php index 536a20c3..25c4bf89 100644 --- a/app/src/Model/CommentsModel.php +++ b/app/src/Model/CommentsModel.php @@ -594,7 +594,7 @@ public function updateApproval($blog_id, $comment_id = null) $params[] = $comment_id; } $sql .= ' AND open_status=' . Config::get('COMMENT.OPEN_STATUS.PENDING'); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } diff --git a/app/src/Model/DBInterface.php b/app/src/Model/DBInterface.php deleted file mode 100644 index c3b60638..00000000 --- a/app/src/Model/DBInterface.php +++ /dev/null @@ -1,32 +0,0 @@ - DBInterface::RESULT_ALL); + $options = array('result' => PDOQuery::RESULT_ALL); return $this->findSql($sql, $params, $options); } @@ -387,7 +387,7 @@ public function increaseCommentCount($blog_id, $entry_id) { $sql = 'UPDATE ' . $this->getTableName() . ' SET comment_count=comment_count+1 WHERE blog_id=? AND id=?'; $params = array($blog_id, $entry_id); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } @@ -401,7 +401,7 @@ public function decreaseCommentCount($blog_id, $entry_id) { $sql = 'UPDATE ' . $this->getTableName() . ' SET comment_count=comment_count-1 WHERE blog_id=? AND id=? AND comment_count>0'; $params = array($blog_id, $entry_id); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } diff --git a/app/src/Model/MSDB.php b/app/src/Model/MSDB.php deleted file mode 100644 index a40b727d..00000000 --- a/app/src/Model/MSDB.php +++ /dev/null @@ -1,180 +0,0 @@ -master) { - if (DB_CONNECT_LIB === 'PDO') { - $this->master = new PDOWrap( - Config::get('MASTER_DB.HOST'), - Config::get('MASTER_DB.PORT'), - Config::get('MASTER_DB.USER'), - Config::get('MASTER_DB.PASSWORD'), - Config::get('MASTER_DB.DATABASE'), - Config::get('DB_CHARSET') - ); - } - if (DB_CONNECT_LIB === 'mysqli') { - $this->master = new MySqliWrap( - Config::get('MASTER_DB.HOST'), - Config::get('MASTER_DB.PORT'), - Config::get('MASTER_DB.USER'), - Config::get('MASTER_DB.PASSWORD'), - Config::get('MASTER_DB.DATABASE'), - Config::get('DB_CHARSET') - ); - } - } - return $this->master; - } - - private function getSlaveDB() - { - if (!$this->slave) { - if (DB_CONNECT_LIB === 'PDO') { - $this->slave = new PDOWrap( - Config::get('SLAVE_DB.HOST'), - Config::get('SLAVE_DB.USER'), - Config::get('SLAVE_DB.PASSWORD'), - Config::get('SLAVE_DB.DATABASE'), - Config::get('DB_CHARSET') - ); - } - if (DB_CONNECT_LIB === 'mysqli') { - $this->slave = new MySqliWrap( - Config::get('SLAVE_DB.HOST'), - Config::get('SLAVE_DB.USER'), - Config::get('SLAVE_DB.PASSWORD'), - Config::get('SLAVE_DB.DATABASE'), - Config::get('DB_CHARSET') - ); - } - } - return $this->slave; - } - - /** - * @param bool $isMaster - * @return MySqliWrap|PDOWrap - */ - public function getDB($isMaster = false) - { - // Master/Slave機能のON/OFF - if (!Config::get('IS_MASTER_SLAVE', true)) { - return $this->getMasterDB(); - } - return $isMaster ? $this->getMasterDB() : $this->getSlaveDB(); - } - - public function close() - { - if ($this->master) { - $this->master->close(); - $this->master = null; - } - if ($this->slave) { - $this->slave->close(); - $this->slave = null; - } - } - - /** - * 参照系SQL - * @param string $sql - * @param array $params - * @param array $options - * @return array|false - */ - public function find(string $sql, array $params = [], array $options = []) - { - $_options = array( - 'master' => false, // Masterから取得するかどうか - 'types' => '', // paramsの型設定(sdi) - 'result' => DBInterface::RESULT_ALL, // 戻り値 one/row/all/statement... - ); - $options = array_merge($_options, $options); - $db = $this->getDB($options['master']); - return $db->find($sql, $params, $options); - } - - /** - * 更新系SQL - * @param string $sql - * @param array $params - * @param array $options - * @return false|int|mixed - */ - public function execute(string $sql, array $params = [], array $options = []) - { - $default_options = [ - 'types' => '', // paramsの型設定(sdi) - 'result' => DBInterface::RESULT_AFFECTED, // 戻り値 one/row/all/statement... - ]; - $options = array_merge($default_options, $options); - $db = $this->getMasterDB(); - return $db->execute($sql, $params, $options); - } - - /** - * 複数の更新系SQL - * @param $sql - * @return bool - */ - public function multiExecute($sql) - { - return $this->getDB()->multiExecute($sql); - } - - /** - * 接続処理 - * @param bool $is_charset - * @param bool $is_database - */ - public function connect($is_charset = true, $is_database = true) - { - $this->getDB()->connect($is_charset, $is_database); - } - - /** - * MySQLのバージョンを取得する - */ - public function getVersion() - { - return $this->getDB()->getVersion(); - } - -} - diff --git a/app/src/Model/Model.php b/app/src/Model/Model.php index 9d99ed80..8eea27eb 100644 --- a/app/src/Model/Model.php +++ b/app/src/Model/Model.php @@ -7,7 +7,7 @@ abstract class Model { - const LIKE_WILDCARD = '\\_%'; // MySQL用 + use QueryTrait; private static $loaded = []; public $validates = []; @@ -34,19 +34,6 @@ protected function getAutoIncrementCompositeKey(): string return ""; } - /** - * @return MSDB|null - */ - public function getDB(): ?MSDB - { - return MSDB::getInstance(); - } - - public function close(): void - { - $this->getDB()->close(); - } - /** * 入力チェック処理 * @param array $data 入力データ @@ -102,18 +89,6 @@ public static function load(string $model) return self::$loaded[$model]; } - - /** - * LIKE検索用にワイルドカードのエスケープ - * @param string $str - * @return string - */ - public static function escape_wildcard(string $str): string - { - return addcslashes($str, self::LIKE_WILDCARD); - } - - /** * 配列内が全て数値型かチェック * @param array $array @@ -138,139 +113,6 @@ public function is_numeric_array(array $array): bool return true; } - /** - * @param string $type - * @param array $options - * @return array|false - */ - public function find(string $type, array $options = []) - { - if (!isset($options['options'])) { - $options['options'] = []; - } - if (!isset($options['params'])) { - $options['params'] = []; - } - switch ($type) { - case 'count': - $options['fields'] = 'COUNT(*)'; - $options['limit'] = 1; - $options['options']['result'] = DBInterface::RESULT_ONE; - break; - case 'one': - $options['limit'] = 1; - $options['options']['result'] = DBInterface::RESULT_ONE; - break; - case 'row': - $options['limit'] = 1; - $options['options']['result'] = DBInterface::RESULT_ROW; - break; - case 'list': - $options['options']['result'] = DBInterface::RESULT_LIST; - break; - case 'all': - $options['options']['result'] = DBInterface::RESULT_ALL; - break; - case 'statement': - default: - $options['options']['result'] = DBInterface::RESULT_STAT; - break; - } - $fields = '*'; - if (isset($options['fields'])) { - $fields = is_array($options['fields']) ? implode(',', $options['fields']) : $options['fields']; - } - if (!empty($options['limit']) && isset($options['page'])) { - $fields = 'SQL_CALC_FOUND_ROWS ' . $fields; - } - $sql = 'SELECT ' . $fields . ' FROM ' . $this->getTableName(); - if (!empty($options['from'])) { - if (is_array($options['from'])) { - $sql .= ', ' . implode(',', $options['from']); - } else { - $sql .= ', ' . $options['from']; - } - } - if (isset($options['where']) && $options['where'] != "") { - $sql .= ' WHERE ' . $options['where']; - } - if (isset($options['group']) && $options['group'] != "") { - $sql .= ' GROUP BY ' . $options['group']; - } - if (isset($options['order']) && $options['order'] != "") { - $sql .= ' ORDER BY ' . $options['order']; - } - if (!empty($options['limit'])) { - $sql .= ' LIMIT ' . $options['limit']; - if (isset($options['page'])) { - $sql .= ' OFFSET ' . $options['limit'] * $options['page']; - } else if (isset($options['offset'])) { - $sql .= ' OFFSET ' . $options['offset']; - } - } - return $this->findSql($sql, $options['params'], $options['options']); - } - - /** - * 主キーをキーにしてデータを取得 - * @param int|string|null $id - * @param array $options - * @return array|false - */ - public function findById($id, array $options = []) - { - if (empty($id)) { - return []; - } - $options['where'] = isset($options['where']) ? 'id=? AND ' . $options['where'] : 'id=?'; - $options['params'] = isset($options['params']) ? array_merge([$id], $options['params']) : [$id]; - return $this->find('row', $options); - } - - /** - * idとblog_idの複合キーからデータを取得 - * @param int|string|null $id - * @param string|null $blog_id - * @param array $options - * @return array|false - */ - public function findByIdAndBlogId($id, ?string $blog_id, array $options = []) - { - if (empty($id) || empty($blog_id)) { - return []; - } - $options['where'] = isset($options['where']) ? 'blog_id=? AND id=? AND ' . $options['where'] : 'blog_id=? AND id=?'; - $options['params'] = isset($options['params']) ? array_merge([$blog_id, $id], $options['params']) : [$blog_id, $id]; - return $this->find('row', $options); - } - - /** - * idとuser_idのキーからデータを取得 - * @param $id - * @param int $user_id - * @param array $options - * @return array|false - */ - public function findByIdAndUserId($id, int $user_id, array $options = []) - { - if (empty($id) || empty($user_id)) { - return []; - } - $options['where'] = isset($options['where']) ? 'id=? AND user_id=? AND ' . $options['where'] : 'id=? AND user_id=?'; - $options['params'] = isset($options['params']) ? array_merge([$id, $user_id], $options['params']) : [$id, $user_id]; - return $this->find('row', $options); - } - - /** - * 存在するかどうかを取得 - * @param array $options - * @return bool - */ - public function isExist(array $options = []): bool - { - return !!$this->find('row', $options); - } - /** * ページング用のデータ取得 * @param array $options @@ -278,6 +120,8 @@ public function isExist(array $options = []): bool */ public function getPaging(array $options = []): array { + $count = $this->getFoundRows($options); + if (!isset($options['page']) || !isset($options['limit'])) { Log::error('getPaging options["page"] or options["limit"]が設定されておりません'); return []; @@ -286,8 +130,6 @@ public function getPaging(array $options = []): array $page = $options['page']; $limit = $options['limit']; - $count = $this->getFoundRows(); - $pages = []; $pages['count'] = $count; $pages['max_page'] = ceil($count / $limit); @@ -300,16 +142,6 @@ public function getPaging(array $options = []): array return $pages; } - /** - * SQL_CALC_FOUND_ROWSで見つかった件数を返却する - * @return array|false - */ - public function getFoundRows() - { - $sql = 'SELECT FOUND_ROWS()'; - return $this->findSql($sql, [], array('result' => DBInterface::RESULT_ONE)); - } - /** * ページングのリストを表示する * @param array $paging @@ -324,428 +156,4 @@ public static function getPageList(array $paging): array } return $pages; } - - /** - * @param string $sql - * @param array $params - * @param array $options - * @return array|false - */ - public function findSql(string $sql, array $params = [], array $options = []) - { - return $this->getDB()->find($sql, $params, $options); - } - - /** - * @param array $values - * @param array $options - * @return string|int|false 失敗時:false, 成功時 last insert id - */ - public function insert(array $values, array $options = []) - { - if (!count($values)) { - return 0; - } - $tableName = $this->getTableName(); - $compositeKey = $this->getAutoIncrementCompositeKey(); - if ($compositeKey && empty($values['id']) && !empty($values[$compositeKey])) { - // 複合キーのauto_increment対応 - /** @noinspection SqlResolve */ - /** @noinspection SqlInsertValues */ - $sql = 'INSERT INTO ' . $tableName . ' (id, ' . implode(',', array_keys($values)) . ') ' - . 'VALUES ((SELECT LAST_INSERT_ID(COALESCE(MAX(id), 0)+1) FROM ' . $tableName . ' as auto_increment_temp ' - . 'WHERE ' . $compositeKey . '=?), ' . implode(',', array_fill(0, count($values), '?')) . ')'; - $value = $values[$compositeKey]; - $values = array_values($values); - array_unshift($values, $value); - } else { - // 通常のINSERT - $sql = 'INSERT INTO ' . $tableName . ' (' . implode(',', array_keys($values)) . ') VALUES (' . implode(',', array_fill(0, count($values), '?')) . ')'; - $values = array_values($values); - } - if (!isset($options['result'])) { - $options['result'] = DBInterface::RESULT_INSERT_ID; - } - return $this->executeSql($sql, $values, $options); - } - - /** - * @param array $values - * @param string $where - * @param array $params - * @param array $options - * @return false|int 失敗時:false, 成功時:1 - */ - public function update(array $values, string $where, array $params = [], array $options = []) - { - if (count($values) === 0) { - return 0; - } - $sets = []; - foreach ($values as $key => $value) { - $sets[] = $key . '=?'; - } - $sql = 'UPDATE ' . $this->getTableName() . ' SET ' . implode(',', $sets) . ' WHERE ' . $where; - $params = array_merge(array_values($values), $params); - $options['result'] = DBInterface::RESULT_SUCCESS; - return $this->executeSql($sql, $params, $options); - } - - - /** - * idをキーとした更新 - * @param array $values - * @param $id - * @param array $options - * @return false|int 失敗時:false, 成功時:1 - */ - public function updateById(array $values, $id, array $options = []) - { - return $this->update($values, 'id=?', [$id], $options); - } - - - /** - * idとblog_idをキーとした更新 - * @param array $values - * @param $id - * @param string $blog_id - * @param array $options - * @return false|int 失敗時 False 、成功時1 - */ - public function updateByIdAndBlogId(array $values, $id, string $blog_id, array $options = []) - { - return $this->update($values, 'id=? AND blog_id=?', [$id, $blog_id], $options); - } - - - /** - * @param string $where - * @param array $params - * @param array $options - * @return int|false 失敗時:false, 成功時:1 - */ - public function delete(string $where, array $params = [], array $options = []) - { - $sql = 'DELETE FROM ' . $this->getTableName() . ' WHERE ' . $where; - $options['result'] = DBInterface::RESULT_SUCCESS; - return $this->executeSql($sql, $params, $options); - } - - /** - * idをキーとした削除 - * @param $id - * @param array $options - * @return false|int 失敗時:false, 成功時:1 - */ - public function deleteById($id, array $options = []) - { - return $this->delete('id=?', [$id], $options); - } - - /** - * idとblog_idをキーとした削除 - * @param $id - * @param string $blog_id - * @param array $options - * @return false|int 失敗時:false, 成功時:1 - */ - public function deleteByIdAndBlogId($id, string $blog_id, array $options = []) - { - return $this->delete('blog_id=? AND id=?', [$blog_id, $id], $options); - } - - /** - * idとuser_idをキーとした削除 - * @param $id - * @param int $user_id - * @param array $options - * @return false|int 失敗時:false, 成功時:1 - */ - public function deleteByIdAndUserId($id, int $user_id, array $options = []) - { - return $this->delete('id=? AND user_id=?', [$id, $user_id], $options); - } - - /** - * バルクインサート - * @param array $columns - * @param array $params - * @param array $options - * @return string|int|false false時失敗, 成功時はlast insert idだが、複数INSERTなので活用は難しい - */ - public function multipleInsert(array $columns = [], array $params = [], array $options = []) - { - $sql = 'INSERT INTO ' . $this->getTableName() . ' (' . implode(',', $columns) . ') VALUES '; - $len = count($params) / count($columns); - $sql_array = []; - for ($i = 0; $i < $len; $i++) { - $sql_array[] = '(' . implode(',', array_fill(0, count($columns), '?')) . ')'; - } - $sql .= implode(',', $sql_array); - $options['result'] = DBInterface::RESULT_INSERT_ID; - return $this->executeSql($sql, $params, $options); - } - - /** - * @param string $sql - * @param array $params - * @param array $options - * @return mixed|false 失敗時False、成功時はOptionにより不定 - */ - public function executeSql(string $sql, array $params = [], array $options = []) - { - return $this->getDB()->execute($sql, $params, $options); - } - - /** - * 階層構造の一覧取得 - * @param array $options - * @return array|false - */ - public function findNode(array $options) - { - $options['order'] = 'lft ASC'; - $nodes = $this->find('all', $options); - - // levelを付与 - $level = 0; - $levels = []; - foreach ($nodes as $key => $value) { - // 最初のノード - if ($level == 0) { - $levels[] = $value; - $nodes[$key]['level'] = $level = count($levels); - continue; - } - // left=left+1であれば子供ノードとして解釈 - if ($value['lft'] == $levels[$level - 1]['lft'] + 1) { - $levels[] = $value; - $nodes[$key]['level'] = $level = count($levels); - continue; - } - // left=right+1であれば兄弟ノードとして解釈 - if ($value['lft'] == $levels[$level - 1]['rgt'] + 1) { - $levels[$level - 1] = $value; - $nodes[$key]['level'] = $level; - continue; - } - // 兄弟ノードになるまで階層を遡る - while (array_pop($levels)) { - $level = count($levels); - if ($value['lft'] == $levels[$level - 1]['rgt'] + 1) { - $levels[$level - 1] = $value; - $nodes[$key]['level'] = $level; - break; - } - } - } - return $nodes; - } - - /** - * 階層構造の追加 - * @param array $data 追加するノード情報 - * @param string $where 親ノード検索時のwhere句 - * @param array $params 親ノード検索時のバインドデータ - * @param array $options - * @return string|int|false falseか、Last insert id - */ - public function addNode(array $data = [], string $where = '', array $params = [], array $options = []) - { - // 親として末尾に追加する場合 - if (empty($data['parent_id'])) { - $max_right = $this->find('one', array('fields' => 'MAX(rgt)', 'where' => $where, 'params' => $params, 'options' => $options)); - // 親として末尾に追加 - $data['lft'] = $max_right + 1; - $data['rgt'] = $max_right + 2; - return $this->insert($data); - } - - // 親の子供として末尾に追加する場合 - $parent = $this->findById($data['parent_id'], array('fields' => 'rgt', 'where' => $where, 'params' => $params, 'options' => $options)); - if (!$parent) { - return false; - } - $right = $parent['rgt']; - - // 挿入する場所を確保する - $table = $this->getTableName(); - if ($where != "") { - $where .= ' AND '; - } - /** @noinspection SqlResolve */ - /** @noinspection SqlCaseVsIf */ - $updateSql = << {$right} THEN lft + 2 ELSE lft END, - rgt = CASE WHEN rgt >= {$right} THEN rgt + 2 ELSE rgt END - WHERE {$where} rgt >= {$right} - SQL; - - if (!$this->executeSql($updateSql, $params)) { - return false; - } - - // 子供として末尾に追加 - $data['lft'] = $right; - $data['rgt'] = $right + 1; - return $this->insert($data); - } - - /** - * 階層構造の更新 - * @param array $data - * @param string|int $id - * @param string $where - * @param array $params - * @param array $options - * @return false|int - */ - public function updateNodeById(array $data, string $id, string $where = '', array $params = [], array $options = []) - { - $idWhere = $where ? 'id=? AND ' . $where : 'id=?'; - - // 自身取得 - $self_params = array_merge(array($id), $params); - $self = $this->find('row', array('where' => $idWhere, 'params' => $self_params, 'options' => $options)); - if (!$self) { - return false; - } - - // 親が変更されていない場合そのまま更新 - if ($self['parent_id'] == $data['parent_id']) { - return $this->update($data, $idWhere, $self_params, $options); - } - - if ($self['parent_id'] && empty($data['parent_id'])) { - // 親から外れた時 - $parent = []; - $parent['lft'] = $parent['rgt'] = $this->find('one', array('fields' => 'MAX(rgt)', 'where' => $where, 'params' => $params, 'options' => $options)) + 1; - } else { - // 変更先の親を取得 - $parent_params = array_merge(array($data['parent_id']), $params); - $parent = $this->find('row', array('where' => $idWhere, 'params' => $parent_params, 'options' => $options)); - if (!$parent) { - return false; - } - } - - // 変更先の親が自身や自分の子供の場合はエラー - if ($self['lft'] <= $parent['lft'] && $parent['rgt'] <= $self['rgt']) { - return false; - } - - // ノードの変更位置計算 - $self_lft = $self['lft']; - $self_rgt = $self['rgt']; - $parent_rgt = $parent['rgt']; - $space = $self_rgt - $self_lft + 1; - - $table = $this->getTableName(); - $where = $where ? $where . ' AND ' : ''; - if ($self_rgt > $parent_rgt) { - // 自身を左へ移動 - $move = $parent_rgt - $self_lft; - /** @noinspection SqlResolve */ - $sql = << $parent_rgt AND lft < $self_lft - THEN lft + $space - WHEN lft >= $self_lft AND lft < $self_rgt - THEN lft + $move - ELSE lft END, - rgt = CASE - WHEN rgt >= $parent_rgt AND rgt < $self_lft - THEN rgt + $space - WHEN rgt > $self_lft AND rgt <= $self_rgt - THEN rgt + $move - ELSE rgt END - WHERE $where - rgt >= $parent_rgt AND lft < $self_rgt - SQL; - } else { - // 自身を右へ移動 - $move = $parent_rgt - $self_rgt - 1; - /** @noinspection SqlResolve */ - $sql = << $self_rgt AND lft < $parent_rgt - THEN lft - $space - WHEN lft >= $self_lft AND lft < $self_rgt - THEN lft + $move - ELSE lft END, - rgt = CASE - WHEN rgt > $self_rgt AND rgt < $parent_rgt - THEN rgt - $space - WHEN rgt > $self_lft AND rgt <= $self_rgt - THEN rgt + $move - ELSE rgt END - WHERE $where - rgt > $self_lft AND lft < $parent_rgt - SQL; - } - - // 親の位置変更処理 - if (!$this->executeSql($sql, $params, $options)) { - return false; - } - - // 自身の更新処理 - return $this->update($data, $idWhere, $self_params, $options); - } - - /** - * 階層構造のノード削除 - * @param $id - * @param string $where - * @param array $params - * @param array $options - * @return array|false|int|mixed - */ - public function deleteNodeById($id, string $where = '', array $params = [], array $options = []) - { - // 自身取得 - $idWhere = $where ? 'id=? AND ' . $where : 'id=?'; - $self_params = array_merge(array($id), $params); - $self = $this->find('row', array('where' => $idWhere, 'params' => $self_params, 'options' => $options)); - - if (!$self) { - return false; - } - - $self_lft = $self['lft']; - $self_rgt = $self['rgt']; - $space = $self_rgt - $self_lft + 1; - - $table = $this->getTableName(); - $where = $where ? $where . ' AND ' : ''; - - // 削除処理 - $sql = 'DELETE FROM ' . $table . ' WHERE ' . $where . ' lft >= ' . $self_lft . ' AND rgt <= ' . $self_rgt; - if (!$this->executeSql($sql, $params, $options)) { - return false; - } - - // 詰める処理 - /** @noinspection SqlResolve */ - /** @noinspection SqlCaseVsIf */ - $sql = << $self_rgt - THEN lft - $space - ELSE lft END, - rgt = CASE - WHEN rgt > $self_rgt - THEN rgt - $space - ELSE rgt END - WHERE - $where - rgt > $self_rgt - SQL; - return $this->executeSql($sql, $params, $options); - } } diff --git a/app/src/Model/MySqliWrap.php b/app/src/Model/MySqliWrap.php deleted file mode 100644 index 8d8cc06f..00000000 --- a/app/src/Model/MySqliWrap.php +++ /dev/null @@ -1,351 +0,0 @@ -host = $host; - $this->port = $port; - $this->user = $user; - $this->password = $password; - $this->database = $database; - $this->charset = $charset; - } - - /** - * 参照系SQL - * @param string $sql - * @param array $params - * @param array $options - * @return array|false|int|mixed - */ - public function find(string $sql, array $params = [], array $options = []) - { - $_options = array( - 'types' => '', // paramsの型設定(sdi) - 'result' => \Fc2blog\Model\DBInterface::RESULT_ALL, // 戻り値 one/row/all/statement... - ); - $options = array_merge($_options, $options); - try { - $stmt = $this->query($sql, $params, $options['types']); - } catch (\Exception $e) { - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - \Fc2blog\Util\Log::old_log($e->getMessage(), $params, 'error', __FILE__, __LINE__); - } - return false; - } - return $this->result($stmt, $options['result']); - } - - /** - * 更新系SQL - * @param string $sql - * @param array $params - * @param array $options - * @return array|false|int|mixed - */ - public function execute(string $sql, array $params = [], array $options = []) - { - $_options = array( - 'types' => '', // paramsの型設定(sdi) - 'result' => \Fc2blog\Model\DBInterface::RESULT_SUCCESS, // 戻り値 one/row/all/statement... - ); - $options = array_merge($_options, $options); - try { - $stmt = $this->query($sql, $params, $options['types']); - } catch (\Exception $e) { - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - \Fc2blog\Util\Log::old_log($e->getMessage(), $params, 'error', __FILE__, __LINE__); - } - return false; - } - return $this->result($stmt, $options['result']); - } - - /** - * 複数の更新系SQL - */ - public function multiExecute($sql) - { - $sql = preg_replace('/^--.*?\n/m', '', $sql); - $sql = preg_replace('/\/\*.*?\*\//s', '', $sql); - $sqls = explode(';', $sql); - $execute_sqls = array(); - foreach ($sqls as $sql) { - if (trim($sql) !== '') { - $execute_sqls[] = $sql; - } - } - - foreach ($execute_sqls as $sql) { - if ($this->execute($sql) === false) { - return false; - } - } - return true; - } - - /** - * SQLの実行 - * @throws \Exception - */ - private function query($sql, $params = array(), $types = '') - { - $mtime = 0; // SQL実行結果時間取得用 - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - $mtime = microtime(true); - } - - $this->connect(); - - if (!count($params)) { - // SQL文をそのまま実行 - $stmt = $this->db->query($sql); - if (getType($stmt) == 'boolean' && !$stmt) { - throw new \Exception('[query Error]' . print_r($this->db->error, true) . $sql); - } - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - $mtime = sprintf('%0.2fms', (microtime(true) - $mtime) * 1000); - \Fc2blog\Util\Log::old_log('実行時間:' . $mtime . ' ' . $sql, $params, 'sql', __FILE__, __LINE__); - } - return $stmt; - } - - // プリペアドステートメント - $stmt = $this->db->prepare($sql); - if (!$stmt) { - throw new \Exception('[prepare Error]' . $sql); - } - $types = count($params) == strlen($types) ? $types : $this->getBindTypes($params); - $bindParams = array($types); - foreach ($params as $key => $value) { - $bindParams[] = &$params[$key]; - } - $res = call_user_func_array(array($stmt, 'bind_param'), $bindParams); - if (!$stmt->execute()) { - throw new \Exception('[execute Error]' . $sql); - } - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - $mtime = sprintf('%0.2fms', (microtime(true) - $mtime) * 1000); - \Fc2blog\Util\Log::old_log('実行時間:' . $mtime . ' ' . $sql, $params, 'sql', __FILE__, __LINE__); - } - return $stmt; - } - - public function connect($is_charset = true, $is_database = true) - { - // TODO Show Warning message on connect failed. but mysqli throw error, not exception... - if ($this->db == null) { - if ($is_database) { - $this->db = new \mysqli($this->host, $this->user, $this->password, $this->database, (int)$this->port); - } else { - $this->db = new \mysqli($this->host, $this->user, $this->password, null, (int)$this->port); - } - $this->errorCheck('Connect Error'); - if ($is_charset) { - $this->db->set_charset($this->charset); - } - } - } - - public function close() - { - if ($this->db != null) { - $this->db->close(); - $this->db = null; - } - } - - private function errorCheck($msg) - { - if (mysqli_connect_error()) { - throw new \Exception('[' . $msg . '] (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); - } - /* - // PHP 5.2.9 および 5.3.0 より前のバージョンでは $connect_error は動作していない - if ($this->db->connect_errno) { - throw new \Exception('['.$msg . '] (' . $this->db->connect_errno . ') ' . $this->db->connect_error); - } - */ - } - - private function getBindTypes($params) - { - $types = ""; - foreach ($params as $key => $value) { - $type = getType($value); - switch ($type) { - default: - $type = "string"; - case 'boolean': - case 'integer': - case 'double': - case 'string': - $types .= $type[0]; - } - } - return $types; - } - - public function result($stmt, $type) - { - switch ($type) { - // 1カラムのみ取得 - case \Fc2blog\Model\DBInterface::RESULT_ONE : - $one = null; - switch (get_class($stmt)) { - case 'mysqli_stmt': - $one = $this->fetchstatement($stmt, 'one'); - $stmt->close(); - break; - - case 'mysqli_result': - $row = $stmt->fetch_row(); - $one = $row[0]; - $stmt->close(); - break; - } - $one = empty($one) ? 0 : $one; - return $one; - - // 1行のみ取得 - case \Fc2blog\Model\DBInterface::RESULT_ROW : - $row = array(); - switch (get_class($stmt)) { - case 'mysqli_stmt': - $row = $this->fetchstatement($stmt, 'row'); - $stmt->close(); - break; - - case 'mysqli_result': - $row = $stmt->fetch_assoc(); - $stmt->close(); - break; - } - return $row; - - // リスト形式で取得 - case \Fc2blog\Model\DBInterface::RESULT_LIST : - $rows = array(); - switch (get_class($stmt)) { - case 'mysqli_stmt': - $rows = $this->fetchstatement($stmt, 'list'); - $stmt->close(); - break; - - case 'mysqli_result': - while ($row = $stmt->fetch_row()) { - $rows[$row[0]] = $row[1]; - } - $stmt->close(); - break; - } - return $rows; - - - // 全て取得 - case \Fc2blog\Model\DBInterface::RESULT_ALL : - $rows = array(); - switch (get_class($stmt)) { - case 'mysqli_stmt': - $rows = $this->fetchstatement($stmt); - $stmt->close(); - break; - - case 'mysqli_result': - while ($row = $stmt->fetch_assoc()) { - $rows[] = $row; - } - $stmt->close(); - break; - } - return $rows; - - // InsertIDを返却 - case \Fc2blog\Model\DBInterface::RESULT_INSERT_ID : - $insert_id = $this->db->insert_id; - if (getType($stmt) === 'object') { - $stmt->close(); - } - return $insert_id; - - // 影響のあった行数を返却 - case \Fc2blog\Model\DBInterface::RESULT_AFFECTED : - $affected_rows = $this->db->affected_rows; - if (getType($stmt) === 'object') { - $stmt->close(); - } - return $affected_rows; - - // 成功したかどうかを返却 - case \Fc2blog\Model\DBInterface::RESULT_SUCCESS : - return 1; - - case \Fc2blog\Model\DBInterface::RESULT_STAT: - default: - return $stmt; - } - } - - /** - * mysqli_statement用のfetch - */ - private function fetchstatement(&$stmt, $type = 'all') - { - $hits = array(); - $params = array(); - - if (!$stmt->store_result()) { - throw new \Exception('[store_result] error=[' . $stmt->error . ']'); - } - $meta = $stmt->result_metadata(); - while ($field = $meta->fetch_field()) { - $params[] = &$row[$field->name]; - } - call_user_func_array(array($stmt, 'bind_result'), $params); - while ($stmt->fetch()) { - if ($type == 'one') { - return array_shift($row); - } - $c = array(); - foreach ($row as $key => $val) { - $c[$key] = $val; - } - if ($type == 'row') { - return $c; - } - if ($type == 'list') { - $hits[array_shift($c)] = array_shift($c); - } else { - $hits[] = $c; - } - } - return $hits; - } - - public function getVersion() - { - $this->connect(false, false); - $version = explode('-', $this->db->server_info); - return $version[0]; - } -} diff --git a/app/src/Model/PDOConnection.php b/app/src/Model/PDOConnection.php new file mode 100644 index 00000000..fc0bbaa1 --- /dev/null +++ b/app/src/Model/PDOConnection.php @@ -0,0 +1,45 @@ +pdo = static::createConnection(); + } + return self::$instance; + } + + /** @var PDO */ + public $pdo; + + public static function createConnection(): PDO + { + $host = DB_HOST; + $port = DB_PORT; + $user = DB_USER; + $password = DB_PASSWORD; + $database = DB_DATABASE; + $charset = DB_CHARSET; + + return new PDO( + "mysql:host={$host};port={$port};dbname={$database};charset={$charset};", + $user, + $password, + [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, + ] + ); + } +} diff --git a/app/src/Model/PDOQuery.php b/app/src/Model/PDOQuery.php new file mode 100644 index 00000000..5f12c68f --- /dev/null +++ b/app/src/Model/PDOQuery.php @@ -0,0 +1,162 @@ + static::RESULT_ALL], $options); + try { + $stmt = static::query($pdo, $sql, $params); + } catch (PDOException $e) { + Log::error("DB find error " . $e->getMessage() . " {$sql}", [$params]); + throw $e; + } + return static::result($pdo, $stmt, $options['result']); + } + + /** + * 更新系SQLの実行 + * @param PDO $pdo + * @param string $sql + * @param array $params + * @param array $options + * @return array|int + */ + public static function execute(PDO $pdo, string $sql, array $params = [], array $options = []) + { + $options = array_merge(['result' => static::RESULT_SUCCESS], $options); + try { + $stmt = static::query($pdo, $sql, $params); + } catch (PDOException $e) { + Log::error("DB execute error " . $e->getMessage() . " {$sql}", [$params]); + throw $e; + } + return static::result($pdo, $stmt, $options['result']); + } + + /** + * 複数行となるSQLの実行 + * @param PDO $pdo + * @param $sql + * @return bool + */ + public static function multiExecute(PDO $pdo, $sql): bool + { + $sql = preg_replace('/^--.*?\n/m', '', $sql); + $sql = preg_replace('/\/\*.*?\*\//s', '', $sql); + $sql_list = explode(';', $sql); + foreach ($sql_list as $sql) { + if (trim($sql) === '') continue; // 空クエリならスキップ + static::execute($pdo, $sql); + } + return true; + } + + /** + * PDOでSQLの実行 + * @param PDO $pdo + * @param $sql + * @param array $params + * @return false|PDOStatement 成功時PDOStatement + */ + private static function query(PDO $pdo, $sql, array $params = []) + { + if (Config::get('SQL_DEBUG', 0)) { + $mtime = microtime(true); + } + + if (!count($params)) { + $stmt = $pdo->query($sql); + } else { + $stmt = $pdo->prepare($sql); + $stmt->execute($params); + } + + if (isset($mtime) && Config::get('SQL_DEBUG', 0)) { + $mtime = sprintf('%0.2fms', (microtime(true) - $mtime) * 1000); + Log::debug_log("SQL {$mtime} {$sql}", ['params' => $params]); + } + return $stmt; + } + + /** + * 結果内容の変換 TODO いつか削除する + * @param PDO $pdo + * @param $stmt + * @param $type + * @return array|int $typeによって様々な意味の返り値となる + */ + public static function result(PDO $pdo, $stmt, $type) + { + if ($stmt === false) { + return []; + } + + switch ($type) { + // 1カラムのみ取得 + case static::RESULT_ONE : + return $stmt->fetchColumn(); + + // 1行のみ取得 + case static::RESULT_ROW : + return $stmt->fetch(); + + // リスト形式で取得 + case static::RESULT_LIST : + $rows = []; + $stmt->setFetchMode(PDO::FETCH_NUM); + foreach ($stmt as $value) { + $rows[$value[0]] = $value[1]; + } + return $rows; + + // 全て取得 + case static::RESULT_ALL : + return $stmt->fetchAll(); + + // InsertIDを返却 + case static::RESULT_INSERT_ID : + return $pdo->lastInsertId(); + + // 影響のあった行数を返却 + case static::RESULT_AFFECTED : + return $stmt->rowCount(); + + // 成功したかどうかを返却 + case static::RESULT_SUCCESS : + return 1; + + case static::RESULT_STAT: + default: + return $stmt; + } + } +} diff --git a/app/src/Model/PDOWrap.php b/app/src/Model/PDOWrap.php deleted file mode 100644 index c493afd5..00000000 --- a/app/src/Model/PDOWrap.php +++ /dev/null @@ -1,243 +0,0 @@ -host = $host; - $this->port = $port; - $this->user = $user; - $this->password = $password; - $this->database = $database; - $this->charset = $charset; - } - - /** - * 参照系SQL - * @param string $sql - * @param array $params - * @param array $options - * @return mixed - */ - public function find(string $sql, array $params = [], array $options = []) - { - $_options = array( - 'types' => '', // paramsの型設定(sdi) - 'result' => \Fc2blog\Model\DBInterface::RESULT_ALL, // 戻り値 one/row/all/statement... - ); - $options = array_merge($_options, $options); - try { - $stmt = $this->query($sql, $params, $options['types']); - } catch (Exception $e) { - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - \Fc2blog\Util\Log::old_log($e->getMessage(), $params, 'error', __FILE__, __LINE__); - } - return false; - } - return $this->result($stmt, $options['result']); - } - - - /** - * 更新系SQL - * @param string $sql - * @param array $params - * @param array $options - * @return array|false|int - */ - public function execute(string $sql, array $params = [], array $options = []) - { - $_options = array( - 'types' => '', // paramsの型設定(sdi) - 'result' => \Fc2blog\Model\DBInterface::RESULT_SUCCESS, // 戻り値 one/row/all/statement... - ); - $options = array_merge($_options, $options); - try { - $stmt = $this->query($sql, $params, $options['types']); - } catch (Exception $e) { - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - \Fc2blog\Util\Log::old_log($e->getMessage(), $params, 'error', __FILE__, __LINE__); - } - return false; - } - return $this->result($stmt, $options['result']); - } - - /** - * 複数の更新系SQL - */ - public function multiExecute($sql) - { - $sql = preg_replace('/^--.*?\n/m', '', $sql); - $sql = preg_replace('/\/\*.*?\*\//s', '', $sql); - $sqls = explode(';', $sql); - $execute_sqls = array(); - foreach ($sqls as $sql) { - if (trim($sql) !== '') { - $execute_sqls[] = $sql; - } - } - - foreach ($execute_sqls as $sql) { - if ($this->execute($sql) === false) { - return false; - } - } - return true; - } - - /** - * SQLの実行 - * @param $sql - * @param array $params - * @param string $types - * @return PDOStatement|mixed 成功時PDOStatement - * @throws Exception - */ - private function query($sql, $params = array(), $types = '') - { - $mtime = 0; // SQL実行結果時間取得用 - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - $mtime = microtime(true); - } - - $this->connect(); - - if (!count($params)) { - // SQL文をそのまま実行 - $stmt = $this->db->query($sql); - if (getType($stmt) == 'boolean' && !$stmt) { - throw new Exception('[query Error]' . print_r($this->db->errorInfo(), true) . $sql); - } - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - $mtime = sprintf('%0.2fms', (microtime(true) - $mtime) * 1000); - \Fc2blog\Util\Log::old_log('実行時間:' . $mtime . ' ' . $sql, $params, 'sql', __FILE__, __LINE__); - } - return $stmt; - } - - // プリペアドステートメント - $stmt = $this->db->prepare($sql); - if (!$stmt) { - throw new Exception('[prepare Error]' . $sql); - } - $stmt->execute($params); - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - $mtime = sprintf('%0.2fms', (microtime(true) - $mtime) * 1000); - \Fc2blog\Util\Log::old_log('実行時間:' . $mtime . ' ' . $sql, $params, 'sql', __FILE__, __LINE__); - } - return $stmt; - } - - public function connect($is_charset = true, $is_database = true) - { - if ($this->db == null) { - $dsn = "mysql:host={$this->host};port={$this->port}"; - if ($is_database) { - $dsn = "mysql:host={$this->host};port={$this->port};dbname={$this->database};"; - } - $options = array( - \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, - \PDO::ATTR_EMULATE_PREPARES => false, - ); - if ($is_charset) { - if (version_compare(PHP_VERSION, '5.3.6') < 0) { - $options[\PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES '" . $this->charset . "';"; - } else { - $dsn .= "charset={$this->charset};"; - } - } - $this->db = new \PDO($dsn, $this->user, $this->password, $options); - } - } - - public function close() - { - if ($this->db != null) { - $this->db = null; - } - } - - /** - * @param $stmt - * @param $type - * @return array|int $typeによって様々な意味の返り値となる - */ - public function result($stmt, $type) - { - if ($stmt === false) { - return array(); - } - - switch ($type) { - // 1カラムのみ取得 - case \Fc2blog\Model\DBInterface::RESULT_ONE : - return $stmt->fetchColumn(); - - // 1行のみ取得 - case \Fc2blog\Model\DBInterface::RESULT_ROW : - return $stmt->fetch(); - - // リスト形式で取得 - case \Fc2blog\Model\DBInterface::RESULT_LIST : - $rows = array(); - $stmt->setFetchMode(\PDO::FETCH_NUM); - foreach ($stmt as $value) { - $rows[$value[0]] = $value[1]; - } - return $rows; - - // 全て取得 - case \Fc2blog\Model\DBInterface::RESULT_ALL : - return $stmt->fetchAll(); - - // InsertIDを返却 - case \Fc2blog\Model\DBInterface::RESULT_INSERT_ID : - return $this->db->lastInsertId(); - - // 影響のあった行数を返却 - case \Fc2blog\Model\DBInterface::RESULT_AFFECTED : - return $stmt->rowCount(); - - // 成功したかどうかを返却 - case \Fc2blog\Model\DBInterface::RESULT_SUCCESS : - return 1; - - case \Fc2blog\Model\DBInterface::RESULT_STAT: - default: - return $stmt; - } - } - - /** - * MySQLのバージョンを取得する - */ - public function getVersion() - { - $this->connect(false, false); - $version = explode('-', $this->db->getAttribute(\PDO::ATTR_SERVER_VERSION)); - return $version[0]; - } -} diff --git a/app/src/Model/QueryTrait.php b/app/src/Model/QueryTrait.php new file mode 100644 index 00000000..32c7f6bf --- /dev/null +++ b/app/src/Model/QueryTrait.php @@ -0,0 +1,592 @@ +execute(PDOConnection::getInstance()->pdo, $sql, $params, $options); + } + + /** + * @param string $sql + * @param array $params + * @param array $options + * @return array + * @throw PDOException + */ + public function findSql(string $sql, array $params = [], array $options = []) + { + return (new PDOQuery())->find(PDOConnection::getInstance()->pdo, $sql, $params, $options); + } + + /** + * 指定のOptionでSELECTされる件数を取得 + * @param array $options + * @return int + */ + public function getFoundRows(array $options = []): int + { + unset($options['limit']); + unset($options['offset']); + /** @var PDOStatement $stmt */ + $stmt = $this->find('statement', $options); + return $stmt->rowCount(); + } + + /** + * @param string $type + * @param array $options + * @return array + * @throw PDOException + */ + public function find(string $type, array $options = []) + { + if (!isset($options['options'])) { + $options['options'] = []; + } + if (!isset($options['params'])) { + $options['params'] = []; + } + switch ($type) { + case 'count': + $options['fields'] = 'COUNT(*)'; + $options['limit'] = 1; + $options['options']['result'] = PDOQuery::RESULT_ONE; + break; + case 'one': + $options['limit'] = 1; + $options['options']['result'] = PDOQuery::RESULT_ONE; + break; + case 'row': + $options['limit'] = 1; + $options['options']['result'] = PDOQuery::RESULT_ROW; + break; + case 'list': + $options['options']['result'] = PDOQuery::RESULT_LIST; + break; + case 'all': + $options['options']['result'] = PDOQuery::RESULT_ALL; + break; + case 'statement': + default: + $options['options']['result'] = PDOQuery::RESULT_STAT; + break; + } + $fields = '*'; + if (isset($options['fields'])) { + $fields = is_array($options['fields']) ? implode(',', $options['fields']) : $options['fields']; + } + if (!empty($options['limit']) && isset($options['page'])) { + $fields = 'SQL_CALC_FOUND_ROWS ' . $fields; + } + $sql = 'SELECT ' . $fields . ' FROM ' . $this->getTableName(); + if (!empty($options['from'])) { + if (is_array($options['from'])) { + $sql .= ', ' . implode(',', $options['from']); + } else { + $sql .= ', ' . $options['from']; + } + } + if (isset($options['where']) && $options['where'] != "") { + $sql .= ' WHERE ' . $options['where']; + } + if (isset($options['group']) && $options['group'] != "") { + $sql .= ' GROUP BY ' . $options['group']; + } + if (isset($options['order']) && $options['order'] != "") { + $sql .= ' ORDER BY ' . $options['order']; + } + if (!empty($options['limit'])) { + $sql .= ' LIMIT ' . $options['limit']; + if (isset($options['page'])) { + $sql .= ' OFFSET ' . $options['limit'] * $options['page']; + } else if (isset($options['offset'])) { + $sql .= ' OFFSET ' . $options['offset']; + } + } + return $this->executeSql($sql, $options['params'], $options['options']); + } + + /** + * 主キーをキーにしてデータを取得 + * @param int|string|null $id + * @param array $options + * @return array + */ + public function findById($id, array $options = []) + { + if (empty($id)) { + return []; + } + $options['where'] = isset($options['where']) ? 'id=? AND ' . $options['where'] : 'id=?'; + $options['params'] = isset($options['params']) ? array_merge([$id], $options['params']) : [$id]; + return $this->find('row', $options); + } + + /** + * idとblog_idの複合キーからデータを取得 + * @param int|string|null $id + * @param string|null $blog_id + * @param array $options + * @return array + */ + public function findByIdAndBlogId($id, ?string $blog_id, array $options = []) + { + if (empty($id) || empty($blog_id)) { + return []; + } + $options['where'] = isset($options['where']) ? 'blog_id=? AND id=? AND ' . $options['where'] : 'blog_id=? AND id=?'; + $options['params'] = isset($options['params']) ? array_merge([$blog_id, $id], $options['params']) : [$blog_id, $id]; + return $this->find('row', $options); + } + + /** + * idとuser_idのキーからデータを取得 + * @param $id + * @param int $user_id + * @param array $options + * @return array + */ + public function findByIdAndUserId($id, int $user_id, array $options = []) + { + if (empty($id) || empty($user_id)) { + return []; + } + $options['where'] = isset($options['where']) ? 'id=? AND user_id=? AND ' . $options['where'] : 'id=? AND user_id=?'; + $options['params'] = isset($options['params']) ? array_merge([$id, $user_id], $options['params']) : [$id, $user_id]; + return $this->find('row', $options); + } + + /** + * 存在するかどうかを取得 + * @param array $options + * @return bool + */ + public function isExist(array $options = []): bool + { + return !!$this->find('row', $options); + } + + + /** + * @param array $values + * @param array $options + * @return array|int 失敗時:false, 成功時 last insert id + */ + public function insert(array $values, array $options = []) + { + if (!count($values)) { + return 0; + } + $tableName = $this->getTableName(); + $compositeKey = $this->getAutoIncrementCompositeKey(); + if ($compositeKey && empty($values['id']) && !empty($values[$compositeKey])) { + // 複合キーのauto_increment対応 + /** @noinspection SqlResolve */ + /** @noinspection SqlInsertValues */ + $sql = 'INSERT INTO ' . $tableName . ' (id, ' . implode(',', array_keys($values)) . ') ' + . 'VALUES ((SELECT LAST_INSERT_ID(COALESCE(MAX(id), 0)+1) FROM ' . $tableName . ' as auto_increment_temp ' + . 'WHERE ' . $compositeKey . '=?), ' . implode(',', array_fill(0, count($values), '?')) . ')'; + $value = $values[$compositeKey]; + $values = array_values($values); + array_unshift($values, $value); + } else { + // 通常のINSERT + $sql = 'INSERT INTO ' . $tableName . ' (' . implode(',', array_keys($values)) . ') VALUES (' . implode(',', array_fill(0, count($values), '?')) . ')'; + $values = array_values($values); + } + if (!isset($options['result'])) { + $options['result'] = PDOQuery::RESULT_INSERT_ID; + } + return $this->executeSql($sql, $values, $options); + } + + /** + * @param array $values + * @param string $where + * @param array $params + * @param array $options + * @return array|int 失敗時:false, 成功時:1 + */ + public function update(array $values, string $where, array $params = [], array $options = []) + { + if (count($values) === 0) { + return 0; + } + $sets = []; + foreach ($values as $key => $value) { + $sets[] = $key . '=?'; + } + $sql = 'UPDATE ' . $this->getTableName() . ' SET ' . implode(',', $sets) . ' WHERE ' . $where; + $params = array_merge(array_values($values), $params); + $options['result'] = PDOQuery::RESULT_SUCCESS; + return $this->executeSql($sql, $params, $options); + } + + /** + * idをキーとした更新 + * @param array $values + * @param $id + * @param array $options + * @return array|int 失敗時:false, 成功時:1 + */ + public function updateById(array $values, $id, array $options = []) + { + return $this->update($values, 'id=?', [$id], $options); + } + + /** + * idとblog_idをキーとした更新 + * @param array $values + * @param $id + * @param string $blog_id + * @param array $options + * @return array|int 失敗時 False 、成功時1 + */ + public function updateByIdAndBlogId(array $values, $id, string $blog_id, array $options = []) + { + return $this->update($values, 'id=? AND blog_id=?', [$id, $blog_id], $options); + } + + /** + * @param string $where + * @param array $params + * @param array $options + * @return array|int 失敗時:false, 成功時:1 + */ + public function delete(string $where, array $params = [], array $options = []) + { + $sql = 'DELETE FROM ' . $this->getTableName() . ' WHERE ' . $where; + $options['result'] = PDOQuery::RESULT_SUCCESS; + return $this->executeSql($sql, $params, $options); + } + + /** + * idをキーとした削除 + * @param $id + * @param array $options + * @return array|int 失敗時:false, 成功時:1 + */ + public function deleteById($id, array $options = []) + { + return $this->delete('id=?', [$id], $options); + } + + /** + * idとblog_idをキーとした削除 + * @param $id + * @param string $blog_id + * @param array $options + * @return array|int 失敗時:false, 成功時:1 + */ + public function deleteByIdAndBlogId($id, string $blog_id, array $options = []) + { + return $this->delete('blog_id=? AND id=?', [$blog_id, $id], $options); + } + + /** + * idとuser_idをキーとした削除 + * @param $id + * @param int $user_id + * @param array $options + * @return array|int 失敗時:false, 成功時:1 + */ + public function deleteByIdAndUserId($id, int $user_id, array $options = []) + { + return $this->delete('id=? AND user_id=?', [$id, $user_id], $options); + } + + /** + * バルクインサート + * @param array $columns + * @param array $params + * @param array $options + * @return array|int false時失敗, 成功時はlast insert idだが、複数INSERTなので活用は難しい + */ + public function multipleInsert(array $columns = [], array $params = [], array $options = []) + { + $sql = 'INSERT INTO ' . $this->getTableName() . ' (' . implode(',', $columns) . ') VALUES '; + $len = count($params) / count($columns); + $sql_array = []; + for ($i = 0; $i < $len; $i++) { + $sql_array[] = '(' . implode(',', array_fill(0, count($columns), '?')) . ')'; + } + $sql .= implode(',', $sql_array); + $options['result'] = PDOQuery::RESULT_INSERT_ID; + return $this->executeSql($sql, $params, $options); + } + + + /** + * 階層構造の一覧取得 + * @param array $options + * @return array + */ + public function findNode(array $options) + { + $options['order'] = 'lft ASC'; + $nodes = $this->find('all', $options); + + // levelを付与 + $level = 0; + $levels = []; + foreach ($nodes as $key => $value) { + // 最初のノード + if ($level == 0) { + $levels[] = $value; + $nodes[$key]['level'] = $level = count($levels); + continue; + } + // left=left+1であれば子供ノードとして解釈 + if ($value['lft'] == $levels[$level - 1]['lft'] + 1) { + $levels[] = $value; + $nodes[$key]['level'] = $level = count($levels); + continue; + } + // left=right+1であれば兄弟ノードとして解釈 + if ($value['lft'] == $levels[$level - 1]['rgt'] + 1) { + $levels[$level - 1] = $value; + $nodes[$key]['level'] = $level; + continue; + } + // 兄弟ノードになるまで階層を遡る + while (array_pop($levels)) { + $level = count($levels); + if ($value['lft'] == $levels[$level - 1]['rgt'] + 1) { + $levels[$level - 1] = $value; + $nodes[$key]['level'] = $level; + break; + } + } + } + return $nodes; + } + + /** + * 階層構造の追加 + * @param array $data 追加するノード情報 + * @param string $where 親ノード検索時のwhere句 + * @param array $params 親ノード検索時のバインドデータ + * @param array $options + * @return array|false|int falseか、Last insert id + */ + public function addNode(array $data = [], string $where = '', array $params = [], array $options = []) + { + // 親として末尾に追加する場合 + if (empty($data['parent_id'])) { + $max_right = $this->find('one', array('fields' => 'MAX(rgt)', 'where' => $where, 'params' => $params, 'options' => $options)); + // 親として末尾に追加 + $data['lft'] = $max_right + 1; + $data['rgt'] = $max_right + 2; + return $this->insert($data); + } + + // 親の子供として末尾に追加する場合 + $parent = $this->findById($data['parent_id'], array('fields' => 'rgt', 'where' => $where, 'params' => $params, 'options' => $options)); + if (!$parent) { + return false; + } + $right = $parent['rgt']; + + // 挿入する場所を確保する + $table = $this->getTableName(); + if ($where != "") { + $where .= ' AND '; + } + /** @noinspection SqlResolve */ + /** @noinspection SqlCaseVsIf */ + $updateSql = << {$right} THEN lft + 2 ELSE lft END, + rgt = CASE WHEN rgt >= {$right} THEN rgt + 2 ELSE rgt END + WHERE {$where} rgt >= {$right} + SQL; + + if (!$this->executeSql($updateSql, $params)) { + return false; + } + + // 子供として末尾に追加 + $data['lft'] = $right; + $data['rgt'] = $right + 1; + return $this->insert($data); + } + + /** + * 階層構造の更新 + * @param array $data + * @param string|int $id + * @param string $where + * @param array $params + * @param array $options + * @return false|int + */ + public function updateNodeById(array $data, string $id, string $where = '', array $params = [], array $options = []) + { + $idWhere = $where ? 'id=? AND ' . $where : 'id=?'; + + // 自身取得 + $self_params = array_merge(array($id), $params); + $self = $this->find('row', array('where' => $idWhere, 'params' => $self_params, 'options' => $options)); + if (!$self) { + return false; + } + + // 親が変更されていない場合そのまま更新 + if ($self['parent_id'] == $data['parent_id']) { + return $this->update($data, $idWhere, $self_params, $options); + } + + if ($self['parent_id'] && empty($data['parent_id'])) { + // 親から外れた時 + $parent = []; + $parent['lft'] = $parent['rgt'] = $this->find('one', array('fields' => 'MAX(rgt)', 'where' => $where, 'params' => $params, 'options' => $options)) + 1; + } else { + // 変更先の親を取得 + $parent_params = array_merge(array($data['parent_id']), $params); + $parent = $this->find('row', array('where' => $idWhere, 'params' => $parent_params, 'options' => $options)); + if (!$parent) { + return false; + } + } + + // 変更先の親が自身や自分の子供の場合はエラー + if ($self['lft'] <= $parent['lft'] && $parent['rgt'] <= $self['rgt']) { + return false; + } + + // ノードの変更位置計算 + $self_lft = $self['lft']; + $self_rgt = $self['rgt']; + $parent_rgt = $parent['rgt']; + $space = $self_rgt - $self_lft + 1; + + $table = $this->getTableName(); + $where = $where ? $where . ' AND ' : ''; + if ($self_rgt > $parent_rgt) { + // 自身を左へ移動 + $move = $parent_rgt - $self_lft; + /** @noinspection SqlResolve */ + $sql = << $parent_rgt AND lft < $self_lft + THEN lft + $space + WHEN lft >= $self_lft AND lft < $self_rgt + THEN lft + $move + ELSE lft END, + rgt = CASE + WHEN rgt >= $parent_rgt AND rgt < $self_lft + THEN rgt + $space + WHEN rgt > $self_lft AND rgt <= $self_rgt + THEN rgt + $move + ELSE rgt END + WHERE $where + rgt >= $parent_rgt AND lft < $self_rgt + SQL; + } else { + // 自身を右へ移動 + $move = $parent_rgt - $self_rgt - 1; + /** @noinspection SqlResolve */ + $sql = << $self_rgt AND lft < $parent_rgt + THEN lft - $space + WHEN lft >= $self_lft AND lft < $self_rgt + THEN lft + $move + ELSE lft END, + rgt = CASE + WHEN rgt > $self_rgt AND rgt < $parent_rgt + THEN rgt - $space + WHEN rgt > $self_lft AND rgt <= $self_rgt + THEN rgt + $move + ELSE rgt END + WHERE $where + rgt > $self_lft AND lft < $parent_rgt + SQL; + } + + // 親の位置変更処理 + if (!$this->executeSql($sql, $params, $options)) { + return false; + } + + // 自身の更新処理 + return $this->update($data, $idWhere, $self_params, $options); + } + + /** + * 階層構造のノード削除 + * @param $id + * @param string $where + * @param array $params + * @param array $options + * @return array|false|int + */ + public function deleteNodeById($id, string $where = '', array $params = [], array $options = []) + { + // 自身取得 + $idWhere = $where ? 'id=? AND ' . $where : 'id=?'; + $self_params = array_merge(array($id), $params); + $self = $this->find('row', array('where' => $idWhere, 'params' => $self_params, 'options' => $options)); + + if (!$self) { + return false; + } + + $self_lft = $self['lft']; + $self_rgt = $self['rgt']; + $space = $self_rgt - $self_lft + 1; + + $table = $this->getTableName(); + $where = $where ? $where . ' AND ' : ''; + + // 削除処理 + $sql = 'DELETE FROM ' . $table . ' WHERE ' . $where . ' lft >= ' . $self_lft . ' AND rgt <= ' . $self_rgt; + if (!$this->executeSql($sql, $params, $options)) { + return false; + } + + // 詰める処理 + /** @noinspection SqlResolve */ + /** @noinspection SqlCaseVsIf */ + $sql = << $self_rgt + THEN lft - $space + ELSE lft END, + rgt = CASE + WHEN rgt > $self_rgt + THEN rgt - $space + ELSE rgt END + WHERE + $where + rgt > $self_rgt + SQL; + return $this->executeSql($sql, $params, $options); + } +} \ No newline at end of file diff --git a/app/src/Model/TagsModel.php b/app/src/Model/TagsModel.php index 3b163015..4a03df7b 100644 --- a/app/src/Model/TagsModel.php +++ b/app/src/Model/TagsModel.php @@ -61,6 +61,8 @@ public function validate(array $data, ?array &$valid_data = [], array $white_lis * @param $data * @param $model * @return bool|string + * @noinspection PhpUnusedParameterInspection + * @noinspection PhpUnused */ public static function uniqueName($value, $option, $key, $data, $model) { @@ -125,9 +127,10 @@ public function getListByNames(string $blog_id, array $tags = []): array * @param $name * @param $blog_id * @param array $options - * @return mixed + * @return array + * @noinspection PhpUnused */ - public function findByNameAndBlogId($name, $blog_id, $options = array()) + public function findByNameAndBlogId($name, $blog_id, array $options = array()) { $options['where'] = isset($options['where']) ? 'name=? AND blog_id=? AND ' . $options['where'] : 'name=? AND blog_id=?'; $options['params'] = isset($options['params']) ? array_merge(array($name, $blog_id), $options['params']) : array($name, $blog_id); @@ -138,9 +141,9 @@ public function findByNameAndBlogId($name, $blog_id, $options = array()) * 良く使用するタグ一覧を取得する * @param $blog_id * @param array $options - * @return mixed + * @return array */ - public function getWellUsedTags($blog_id, $options = array()) + public function getWellUsedTags($blog_id, array $options = array()) { $options['fields'] = 'id, name'; $options['where'] = (isset($options['where']) && $options['where'] != "") ? 'blog_id=? AND ' . $options['where'] : 'blog_id=?'; @@ -170,7 +173,7 @@ public function getEntryTagNames($blog_id, $entry_id) * 記事のタグを取得する * @param $blog_id * @param $entry_id - * @return mixed + * @return array */ public function getEntryTags($blog_id, $entry_id) { @@ -184,7 +187,7 @@ public function getEntryTags($blog_id, $entry_id) SQL; $params = array($blog_id, $entry_id, $blog_id); $options = array(); - $options['result'] = DBInterface::RESULT_ALL; + $options['result'] = PDOQuery::RESULT_ALL; return $this->findSql($sql, $params, $options); } @@ -211,7 +214,7 @@ public function getEntriesTags($blog_id, $entry_ids) SQL; $params = array_merge(array($blog_id), $entry_ids, array($blog_id)); $options = array(); - $options['result'] = DBInterface::RESULT_ALL; + $options['result'] = PDOQuery::RESULT_ALL; $tags = $this->findSql($sql, $params, $options); $entries_tags = array(); @@ -228,7 +231,7 @@ public function getEntriesTags($blog_id, $entry_ids) * 件数を増加させる処理 * @param string $blog_id * @param array $ids - * @return int|false + * @return array|int */ public function increaseCount(string $blog_id, array $ids = array()) { @@ -237,7 +240,7 @@ public function increaseCount(string $blog_id, array $ids = array()) } $sql = 'UPDATE ' . $this->getTableName() . ' SET count=count+1 WHERE blog_id=? AND id IN (' . implode(',', array_fill(0, count($ids), '?')) . ')'; $params = array_merge(array($blog_id), $ids); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } @@ -256,7 +259,7 @@ public function decreaseCount($blog_id, array $ids = []) ' SET count=count-1 WHERE blog_id=? AND count>0 AND id ' . ' IN (' . implode(',', array_fill(0, count($ids), '?')) . ')'; $params = array_merge([$blog_id], $ids); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return # 有効タグ数の数え直し $this->executeSql($sql, $params, $options) && @@ -266,28 +269,29 @@ public function decreaseCount($blog_id, array $ids = []) /** * idとblog_idをキーとした削除 + 付随情報も削除 - * @param $tag_id + * @param $id * @param $blog_id * @param array $options - * @return array|false|int|mixed + * @return array|int */ - public function deleteByIdAndBlogId($tag_id, $blog_id, $options = array()) + public function deleteByIdAndBlogId($id, $blog_id, array $options = array()) { // タグの紐付け情報削除 - Model::load('EntryTags')->delete('blog_id=? AND tag_id=?', array($blog_id, $tag_id)); + (new EntryTagsModel())->delete('blog_id=? AND tag_id=?', array($blog_id, $id)); // 記事本体削除 - return parent::deleteByIdAndBlogId($tag_id, $blog_id, $options); + return parent::deleteByIdAndBlogId($id, $blog_id, $options); } /** * idとblog_idをキーとした削除 + 付随情報も削除 - * @param array $ids + * @param array|int $ids * @param $blog_id * @param array $options * @return bool + * @noinspection PhpUnused */ - public function deleteByIdsAndBlogId($ids, $blog_id, $options = array()) + public function deleteByIdsAndBlogId($ids, $blog_id, array $options = array()) { // 単体ID対応 if (is_numeric($ids)) { diff --git a/app/src/Util/Log.php b/app/src/Util/Log.php index 7af9b991..5112b202 100644 --- a/app/src/Util/Log.php +++ b/app/src/Util/Log.php @@ -32,20 +32,6 @@ public static function getLogger(): LoggerInterface return static::$logger; } - /** - * 過去のDebug::logと互換性を持ったメソッド - * @param string $message - * @param mixed $context - * @param string $class - * @param string $filename - * @param int $line - */ - public static function old_log(string $message, $context, string $class = 'log', string $filename = "-", int $line = 0): void - { - $logger = static::getLogger(); - $logger->debug("[{$class}]{$filename}:{$line} {$message}", [$context]); - } - /** * @param string $message * @param array $context diff --git a/app/src/Web/Controller/Admin/CommonController.php b/app/src/Web/Controller/Admin/CommonController.php index b3f2c3ed..26dd31b1 100644 --- a/app/src/Web/Controller/Admin/CommonController.php +++ b/app/src/Web/Controller/Admin/CommonController.php @@ -9,7 +9,8 @@ use Fc2blog\Model\BlogSettingsModel; use Fc2blog\Model\BlogsModel; use Fc2blog\Model\CommentsModel; -use Fc2blog\Model\MSDB; +use Fc2blog\Model\PDOConnection; +use Fc2blog\Model\PDOQuery; use Fc2blog\Model\PluginsModel; use Fc2blog\Model\UsersModel; use Fc2blog\Web\Cookie; @@ -170,7 +171,7 @@ public function install(Request $request): string $is_connect = true; $connect_message = ''; try { - MSDB::getInstance()->connect(false, false); + PDOConnection::createConnection(); } catch (Exception $e) { $is_connect = false; $connect_message = $e->getMessage(); @@ -178,10 +179,6 @@ public function install(Request $request): string $this->set('is_connect', $is_connect); $this->set('connect_message', $connect_message); - // DB設定確認 - $is_character = version_compare(MSDB::getInstance()->getVersion(), '5.5.0') >= 0 || DB_CHARSET != 'UTF8MB4'; - $this->set('is_character', $is_character); - // ドメイン確認 $is_domain = DOMAIN != 'domain'; $this->set('is_domain', $is_domain); @@ -191,8 +188,8 @@ public function install(Request $request): string $is_gd = function_exists('gd_info'); $this->set('is_gd', $is_gd); - $is_all_ok = $is_write_temp && $is_write_upload && $is_db_connect_lib && $is_connect && $is_character && $is_domain; - $this->set('is_all_ok', $is_all_ok); + $is_all_ok = $is_write_temp && $is_write_upload && $is_db_connect_lib && $is_connect && $is_domain; + $this->set('is_all_ok', $is_all_ok); return 'admin/common/install.twig'; @@ -211,29 +208,18 @@ public function install(Request $request): string } // DB接続確認 - $msdb = MSDB::getInstance(true); try { // DB接続確認(DATABASEの存在判定含む) - $msdb->connect(); + $pdo = PDOConnection::createConnection(); } catch (Exception $e) { - // データベースの作成 - $msdb->close(); - $msdb->connect(false, false); - $sql = 'CREATE DATABASE IF NOT EXISTS ' . DB_DATABASE . ' CHARACTER SET ' . DB_CHARSET; - $msdb->execute($sql); - $msdb->close(); - try { - // 作成できたか確認 - $msdb->connect(); - } catch (Exception $e) { - $this->setErrorMessage(__('Execute `Create database` failed. Please `Create database` your self.')); - $this->redirect($request, $request->baseDirectory . 'common/install?state=0&error=db_create'); - } + $this->setErrorMessage(__('Please set correct the DB connection settings.')); + $this->redirect($request, $request->baseDirectory . 'common/install?state=0&error=db_create'); + return ""; } // テーブルの存在チェック $sql = "SHOW TABLES LIKE 'users'"; - $table = MSDB::getInstance()->find($sql); + $table = PDOQuery::find($pdo, $sql); if (is_countable($table) && count($table)) { // 既にDB登録完了 @@ -246,7 +232,7 @@ public function install(Request $request): string if (DB_CHARSET != 'UTF8MB4') { $sql = str_replace('utf8mb4', strtolower(DB_CHARSET), $sql); } - $res = MSDB::getInstance()->multiExecute($sql); + $res = PDOQuery::multiExecute($pdo, $sql); if ($res === false) { $this->setErrorMessage(__('Create' . ' table failed.')); $this->redirect($request, $request->baseDirectory . 'common/install?state=0&error=table_insert'); @@ -254,7 +240,7 @@ public function install(Request $request): string // DBセットアップ成功チェック $sql = "SHOW TABLES LIKE 'users'"; - $table = MSDB::getInstance()->find($sql); + $table = PDOQuery::find($pdo, $sql); if (!is_countable($table)) { $this->setErrorMessage(__('Create' . ' table failed.')); $this->redirect($request, $request->baseDirectory . 'common/install?state=0&error=table_insert'); diff --git a/app/src/include/bootstrap.php b/app/src/include/bootstrap.php index b0929a64..007be552 100644 --- a/app/src/include/bootstrap.php +++ b/app/src/include/bootstrap.php @@ -4,11 +4,7 @@ define('APP_DIR', realpath(__DIR__ . '/../../') . '/'); // APPディレクトリのパス // DBの接続ライブラリ -if (class_exists('mysqli')) { - define('DB_CONNECT_LIB', 'mysqli'); -} else if (class_exists('PDO')) { - define('DB_CONNECT_LIB', 'PDO'); -} +define('DB_CONNECT_LIB', 'PDO'); // 環境設定読み込み \Fc2blog\Config::read(__DIR__ . '/../config/init_config.php'); diff --git a/app/twig_templates/admin/common/install.twig b/app/twig_templates/admin/common/install.twig index 8651d810..050a2434 100644 --- a/app/twig_templates/admin/common/install.twig +++ b/app/twig_templates/admin/common/install.twig @@ -78,7 +78,7 @@ {% if not is_db_connect_lib %} NG!
-

{{ _('Please enable pdo or mysqli') }}

+

{{ _('Please enable pdo') }}

{% endif %} @@ -121,24 +121,6 @@ - {% if is_connect %} -
  • - {{ _('Character code check of MySQL') }} . . . - {% if is_character %} - OK - {% endif %} - {% if not is_character %} - NG! -
    -

    - {{ _('You can not use the character code of UTF8MB4 because the version of MySQL is older') }}
    - {{ _('Please change to UTF8 DB_CHARSET') }}
    - {{ _('Example') }}) define('DB_CHARSET', 'UTF8'); -

    - {% endif %} -
  • - {% endif %} -
  • {{ _('Check the configuration of the domain') }} . . . {% if is_domain %} diff --git a/dist_zip/installer/fc2blog_installer.php b/dist_zip/installer/fc2blog_installer.php index 2d919a21..7ce70e51 100644 --- a/dist_zip/installer/fc2blog_installer.php +++ b/dist_zip/installer/fc2blog_installer.php @@ -67,9 +67,6 @@ if (!extension_loaded('PDO')) { $list[] = "PDO notfound. "; } - if (!extension_loaded('mysqli')) { - $list[] = "mysqli notfound. "; - } if (!extension_loaded('mbstring')) { $list[] = "mbstring notfound. "; } diff --git a/tests/App/Controller/Admin/Common/InstallTest.php b/tests/App/Controller/Admin/Common/InstallTest.php index 30e9dd3c..d7ad92c9 100644 --- a/tests/App/Controller/Admin/Common/InstallTest.php +++ b/tests/App/Controller/Admin/Common/InstallTest.php @@ -45,7 +45,6 @@ public function testInstallCheck(): void $this->assertTrue($d['is_db_connect_lib']); $this->assertTrue($d['is_connect']); $this->assertEquals(0, strlen($d['connect_message'])); - $this->assertTrue($d['is_character']); $this->assertTrue($d['is_domain']); $this->assertTrue($d['is_gd']); $this->assertTrue($d['is_all_ok']); @@ -82,8 +81,6 @@ public function testInstallFailCheck(): void // 確認がむずかしい $this->assertEquals(0, strlen($d['connect_message'])); // 確認がむずかしい - $this->assertTrue($d['is_character']); - // 確認がむずかしい $this->assertTrue($d['is_domain']); // 確認がむずかしい $this->assertTrue($d['is_gd']);