/var/www/html_us/wp-content/plugins/woocommerce/src/Internal/Logging/SafeGlobalFunctionProxy.php


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<?php

declare(strict_types=1);

namespace 
Automattic\WooCommerce\Internal\Logging;

/**
 * SafeGlobalFunctionProxy Class
 *
 * This class creates a wrapper for non-built-in functions for safety.
 *
 * @since 9.4.0
 * @package Automattic\WooCommerce\Internal\Logging
 */
class SafeGlobalFunctionProxy {

    
/**
     * Load missing function if we know where to find it.
     * Modify this file to add more functions to the map.
     *
     * @param string $name The name of the function to load.
     * @return void
     * @throws \Exception If the function is missing and could not be loaded.
     */
    
private static function maybe_load_missing_function$name ) {
        
$function_map = array(
            
'wp_parse_url'            => ABSPATH WPINC '/http.php',
            
'home_url'                => ABSPATH WPINC '/link-template.php',
            
'get_bloginfo'            => ABSPATH WPINC '/general-template.php',
            
'get_option'              => ABSPATH WPINC '/option.php',
            
'get_site_transient'      => ABSPATH WPINC '/option.php',
            
'set_site_transient'      => ABSPATH WPINC '/option.php',
            
'wp_safe_remote_post'     => ABSPATH WPINC '/http.php',
            
'is_wp_error'             => ABSPATH WPINC '/load.php',
            
'get_plugin_updates'      => array( ABSPATH 'wp-admin/includes/update.php'ABSPATH 'wp-admin/includes/plugin.php' ),
            
'wp_get_environment_type' => ABSPATH WPINC '/load.php',
            
'wp_json_encode'          => ABSPATH WPINC '/functions.php',
            
'wc_get_logger'           => WC_ABSPATH 'includes/class-wc-logger.php',
            
'wc_print_r'              => WC_ABSPATH 'includes/wc-core-functions.php',
        );

        if ( ! 
function_exists$name ) ) {
            if ( isset( 
$function_map$name ] ) ) {
                
$files = (array) $function_map$name ];
                foreach ( 
$files as $file ) {
                    require_once 
$file;
                }
            } else {
                throw new 
\Exceptionsprintf'Function %s does not exist and could not be loaded.'esc_html$name ) ) );
            }
        }
    }

    
/**
     * Proxy for trapping all calls on SafeGlobalFunctionProxy.
     * Use this for calling WP and WC global functions safely.
     * Example usage:
     *
     * SafeGlobalFunctionProxy::wp_parse_url('https://example.com', PHP_URL_PATH);
     *
     * @since 9.4.0
     * @param string $name The name of the function to call.
     * @param array  $arguments The arguments to pass to the function.
     * @return mixed The result of the function call, or null if an error occurs.
     */
    
public static function __callStatic$name$arguments ) {
        
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler -- Custom error handler is necessary to convert errors to exceptions
        
set_error_handler(
            static function ( 
int $typestring $messagestring $fileint $line ) {
                if ( 
__FILE__ === $file ) {
                    
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace -- Used to adjust file and line number for accurate error reporting
                    
$trace debug_backtraceDEBUG_BACKTRACE_IGNORE_ARGS);
                    
$file  $trace[2]['file'] ?? $file;
                    
$line  $trace[2]['line'] ?? $line;
                }
                
$sanitized_message filter_var$messageFILTER_SANITIZE_FULL_SPECIAL_CHARS );
                
// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- $message sanitised above. we don't want to rely on esc_html since it's not a PHP built-in
                
throw new \ErrorException$sanitized_message0$type$file$line );
            }
        );

        try {
            
self::maybe_load_missing_function$name );
            
$results call_user_func_array$name$arguments );
        } catch ( 
\Throwable $e ) {
            
self::log_wrapper_error$name$e->getMessage(), $arguments );
            
$results null;
        } finally {
            
restore_error_handler();
        }

        return 
$results;
    }

    
/**
     * Log wrapper function errors to "local logging" for debugging.
     *
     * @param string $function_name The name of the wrapped function.
     * @param string $error_message The error message.
     * @param array  $context       Additional context for the error.
     */
    
protected static function log_wrapper_error$function_name$error_message$context = array() ) {
        
self::maybe_load_missing_function'wc_get_logger' );

        
wc_get_logger()->error(
            
'[Wrapper function error] ' sprintf'Error in %s: %s'$function_name$error_message ),
            
array_merge(
                array(
                    
'function' => $function_name,
                    
'source'   => 'remote-logging',
                ),
                
$context
            
)
        );
    }
}