HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
File: /var/www/html/insiders/wp-load/wp-content/plugins/internal-links/database/databasecollation.php
<?php

namespace ILJ\Database;

/**
 * Database wrapper for the database collation tool fix.
 *
 * @package ILJ\Database
 * @since   2.24.4
 */
class DatabaseCollation {

	const ILJ_DEFAULT_COLLATION = 'utf8mb4_unicode_ci';
	const ILJ_DEFAULT_CHARSET_COLLATE = 'DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci';

	/**
	 * Get Collation to update to
	 *
	 * @param  bool $for_linkindex This parameter determines if the function is used for database creation or not.
	 * @return string
	 */
	public static function get_collation($for_linkindex = false) {
		global $wpdb;
		$collation = self::ILJ_DEFAULT_COLLATION;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- We need to use a direct query here.
		$query = $wpdb->prepare("SELECT t.table_collation AS TABLE_COLLATION, CCSA.CHARACTER_SET_NAME AS CHARACTER_SET_NAME FROM information_schema.tables AS t JOIN information_schema.collation_character_set_applicability AS CCSA ON t.table_collation = CCSA.collation_name WHERE t.table_schema = DATABASE() AND t.table_name = %s", $wpdb->posts);
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- We need to use a direct query here.
		$result = $wpdb->get_row($query);
		
		if (!empty($result) && isset($result->TABLE_COLLATION, $result->CHARACTER_SET_NAME)) {
			if ($for_linkindex) {
				$collation = "DEFAULT CHARACTER SET " . $result->CHARACTER_SET_NAME . " COLLATE " . $result->TABLE_COLLATION;
				return $collation;
			} else {
				return $result->TABLE_COLLATION;
			}
		}

		return $for_linkindex ? self::ILJ_DEFAULT_CHARSET_COLLATE : self::ILJ_DEFAULT_COLLATION;
	}

	/**
	 * Modify the database collation
	 *
	 * @return void
	 */
	public static function modify_collation() {
		global $wpdb;
		$collation = self::get_collation();

		$sql = "SHOW TABLES LIKE '{$wpdb->prefix}ilj_%'";

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- Direct query is required to check table existence, and caching is not applicable.
		$res = $wpdb->get_col($sql);
		if (null !== $res) {
			foreach ($res as $table) {
				self::modify_table($table, $collation);
			}
			
		}
	}

	/**
	 * Modify the collation per database table
	 *
	 * @param  string $table          Name of the table to alter.
	 * @param  string $collation_term Collation term to update to.
	 * @return void
	 */
	private static function modify_table($table, $collation_term) {
		global $wpdb;
		$sql = "SHOW CREATE TABLE `{$table}`";
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- Direct query is required for schema retrieval, and caching does not apply.
		$create_table_res = $wpdb->get_row($sql, ARRAY_A);
		$create_table = $create_table_res['Create Table'];

		// determine current collation value
		$old_coll = '';
		preg_match('/ COLLATE=([a-zA-Z0-9._-]+)/i', $create_table, $collate_match);
		if (isset($collate_match[1]) && "" != $collate_match[1]) {
			$old_coll = $collate_match[1];
		}

		// check table collation and modify if it's an undesired algorithm
		if ($old_coll != $collation_term) {
			$sql = "ALTER TABLE `{$table}` COLLATE={$collation_term}";
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- Direct query is necessary for altering table structure; caching is not applicable for schema changes.
			$wpdb->query($sql);
		}

		$sql = "SHOW FULL COLUMNS FROM `{$table}`";
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- Direct query is necessary for retrieving table schema, caching is not applicable for this type of query.
		$columns_res = $wpdb->get_results($sql, ARRAY_A);
		if (null !== $columns_res) {
			foreach ($columns_res as $row) {
				// Skip non text fields.
				if (false === stripos($row['Type'], 'text')
					&& false === stripos($row['Type'], 'char')
					&& false === stripos($row['Type'], 'enum')
				) {
					continue;
				}

				if ($row['Collation'] != $collation_term) {
					$null = 'NO' === $row['Null'] ? 'NOT NULL' : 'NULL';
					$default = (null !== $row['Default']) ? " DEFAULT '{$row['Default']}' " : '';
					$sql = "ALTER TABLE `{$table}`
						CHANGE `{$row['Field']}` `{$row['Field']}` {$row['Type']} COLLATE {$collation_term} {$null} {$default}";
					// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- Direct query necessary for ALTER TABLE operation, caching is not applicable.
					$wpdb->query($sql);
				}
			}
		}
	}
}