d36bb954d1
Baseline before backporting wp-data-optimizer v3.0.1-v3.4.6. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
166 lines
4.5 KiB
PHP
166 lines
4.5 KiB
PHP
<?php
|
||
/**
|
||
* TMDO_Type_Caster - 型別轉換器
|
||
*
|
||
* 負責:
|
||
* - PHP → DB 序列化(寫入)
|
||
* - DB → PHP 反序列化(讀取)
|
||
* - wpdb format string 生成
|
||
* - 型別驗證與清理
|
||
*
|
||
* @package WP_Data_Optimizer
|
||
*/
|
||
|
||
// phpcs:disable Squiz.Commenting,Generic.Commenting,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber,Generic.CodeAnalysis.UnusedFunctionParameter,Generic.CodeAnalysis.EmptyStatement,Squiz.PHP.DisallowMultipleAssignments,Squiz.PHP.DisallowSizeFunctionsInLoops,WordPress.WP.I18n.MissingTranslatorsComment,WordPress.PHP.NoSilencedErrors,WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents,Squiz.PHP.CommentedOutCode,Universal.NamingConventions.NoReservedKeywordParameterNames,WordPress.PHP.YodaConditions,Squiz.Commenting.InlineComment.InvalidEndChar -- PR-1 ported from UAE; cleanup PR scheduled.
|
||
|
||
|
||
defined( 'ABSPATH' ) || exit;
|
||
|
||
final class TMDO_Type_Caster {
|
||
|
||
/**
|
||
* PHP → DB 轉換(寫入)
|
||
*/
|
||
public static function to_db( $value, array $field_def ) {
|
||
$type = $field_def['type'] ?? 'text';
|
||
|
||
// null 值處理
|
||
if ( $value === null ) {
|
||
if ( ! empty( $field_def['required'] ) ) {
|
||
return $field_def['default'] ?? '';
|
||
}
|
||
return null;
|
||
}
|
||
|
||
switch ( $type ) {
|
||
case 'integer':
|
||
return (int) $value;
|
||
|
||
case 'decimal':
|
||
return (float) $value;
|
||
|
||
case 'boolean':
|
||
return self::to_bool( $value ) ? 1 : 0;
|
||
|
||
case 'date':
|
||
return self::format_date( $value, 'Y-m-d' );
|
||
|
||
case 'datetime':
|
||
case 'timestamp':
|
||
return self::format_date( $value, 'Y-m-d H:i:s' );
|
||
|
||
case 'json':
|
||
if ( is_string( $value ) ) {
|
||
// 若已是 JSON 字串則直接儲存(驗證後)
|
||
$decoded = json_decode( $value, true );
|
||
if ( json_last_error() === JSON_ERROR_NONE ) {
|
||
return $value;
|
||
}
|
||
}
|
||
return wp_json_encode( $value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
|
||
|
||
case 'enum':
|
||
$options = $field_def['options'] ?? array();
|
||
$str = (string) $value;
|
||
return ( ! empty( $options ) && in_array( $str, $options, true ) ) ? $str : ( $field_def['default'] ?? '' );
|
||
|
||
case 'binary':
|
||
return $value;
|
||
|
||
case 'text':
|
||
return (string) $value;
|
||
|
||
case 'textarea':
|
||
return (string) $value;
|
||
|
||
default:
|
||
// 未知型別:嘗試序列化(向後相容 WordPress get_metadata 行為)
|
||
return maybe_serialize( $value );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* DB → PHP 轉換(讀取)
|
||
*/
|
||
public static function from_db( $value, array $field_def ) {
|
||
$type = $field_def['type'] ?? 'text';
|
||
|
||
if ( $value === null ) {
|
||
return null;
|
||
}
|
||
|
||
switch ( $type ) {
|
||
case 'integer':
|
||
return (int) $value;
|
||
|
||
case 'decimal':
|
||
return (float) $value;
|
||
|
||
case 'boolean':
|
||
return (bool) (int) $value;
|
||
|
||
case 'date':
|
||
case 'datetime':
|
||
case 'timestamp':
|
||
return (string) $value;
|
||
|
||
case 'json':
|
||
$decoded = json_decode( (string) $value, true );
|
||
return ( json_last_error() === JSON_ERROR_NONE ) ? $decoded : $value;
|
||
|
||
case 'enum':
|
||
case 'text':
|
||
case 'textarea':
|
||
return (string) $value;
|
||
|
||
default:
|
||
// v2.13.3: object-injection-safe unserialize (fixes L-DESER-1).
|
||
return TMDO_Safe_Unserialize::run( $value );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* wpdb format 字串(%s / %d / %f)
|
||
*/
|
||
public static function get_wpdb_format( string $type ): string {
|
||
return match ( $type ) {
|
||
'integer', 'boolean' => '%d',
|
||
'decimal' => '%f',
|
||
default => '%s',
|
||
};
|
||
}
|
||
|
||
// ─────────────────────────────────────────────────────────
|
||
// 工具方法
|
||
// ─────────────────────────────────────────────────────────
|
||
|
||
private static function to_bool( $value ): bool {
|
||
if ( is_bool( $value ) ) {
|
||
return $value;
|
||
}
|
||
if ( is_numeric( $value ) ) {
|
||
return (int) $value !== 0;
|
||
}
|
||
$str = strtolower( trim( (string) $value ) );
|
||
return in_array( $str, array( 'true', 'yes', 'y', '1', 'on' ), true );
|
||
}
|
||
|
||
private static function format_date( $value, string $format ): ?string {
|
||
if ( $value === '' || $value === null ) {
|
||
return null;
|
||
}
|
||
|
||
// 接受 Unix timestamp
|
||
if ( is_numeric( $value ) ) {
|
||
return gmdate( $format, (int) $value );
|
||
}
|
||
|
||
$ts = strtotime( (string) $value );
|
||
if ( $ts === false ) {
|
||
return null;
|
||
}
|
||
|
||
return gmdate( $format, $ts );
|
||
}
|
||
}
|