?AlkantarClanX12
| Current Path : /home/rankinh/mariage-reunion-refonte/wp-content/plugins/backwpup/inc/Utils/ |
| Current File : /home/rankinh/mariage-reunion-refonte/wp-content/plugins/backwpup/inc/Utils/BackWPupHelpers.php |
<?php
namespace BackWPup\Utils;
use BackWPup;
class BackWPupHelpers {
/**
* Cache for resolved component paths.
*
* @var array
*/
private static $component_path_cache = [];
/**
* Render or return a component's HTML.
*
* @param string $component The name of the component file to include.
* @param array $args Variables to pass to the component.
* @param bool $return Whether to return the HTML instead of echoing it.
*
* @return string|null HTML content of the component if `$return` is true; otherwise, null.
*/
public static function component( string $component, array $args = [], bool $return = false ) { // @phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.returnFound
$sanitized_component = sanitize_text_field( $component );
if ( ! isset( self::$component_path_cache[ 'c:' . $sanitized_component ] ) ) {
// Explicitly reject traversal-like inputs (e.g., "..", "../", "..\").
if ( self::contains_path_traversal( $sanitized_component ) ) {
error_log( "Component name contains disallowed path traversal sequence: {$sanitized_component}" ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
return null;
}
$filename = $sanitized_component . '.php';
$path = realpath( untrailingslashit( BackWPup::get_plugin_data( 'plugindir' ) ) . '/components/' . $filename );
$allowed_dir = realpath( untrailingslashit( BackWPup::get_plugin_data( 'plugindir' ) ) . '/components/' );
if ( false === $path || false === $allowed_dir ) {
error_log( "Component file not found or outside allowed directory: {$filename}" ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
return null;
}
// Ensure the resolved path is within the allowed components directory, using a directory-boundary-safe check.
$allowed_dir = rtrim( $allowed_dir, DIRECTORY_SEPARATOR );
if ( 0 !== strpos( $path, $allowed_dir . DIRECTORY_SEPARATOR ) ) {
error_log( "Component file not found or outside allowed directory: {$filename}" ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
return null;
}
if ( ! file_exists( $path ) ) {
error_log( "Component file not found: {$path}" ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
return null;
}
self::$component_path_cache[ 'c:' . $sanitized_component ] = $path;
} else {
$path = self::$component_path_cache[ 'c:' . $sanitized_component ];
}
// Extract the arguments for the component context.
// Avoid overwriting built-in variables.
extract( $args, EXTR_SKIP ); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
// Start output buffering.
ob_start();
include $path; // Execute the PHP file in the local context of extracted arguments.
$output = ob_get_clean();
if ( $return ) {
return $output; // Return the output content for further processing.
}
// Directly echo the content if $return is false (default behavior).
echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
return; //phpcs:ignore Squiz.PHP.NonExecutableCode.ReturnNotRequired
}
/**
* Render or return a component's children HTML.
*
* @param string $component The name of the component file to include.
* @param bool $return Whether to return the HTML instead of echoing it.
* @param array $args Variables to pass to the children.
*
* @return string|null HTML content of the component if `$return` is true; otherwise, null.
*/
public static function children( string $component, bool $return = false, array $args = [] ) { // @phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.returnFound
$sanitized_component = sanitize_text_field( $component );
if ( ! isset( self::$component_path_cache[ 'h:' . $sanitized_component ] ) ) {
// Explicitly reject traversal-like inputs (e.g., "..", "../", "..\").
if ( self::contains_path_traversal( $sanitized_component ) ) {
error_log( "Component name contains disallowed path traversal sequence: {$sanitized_component}" ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
return null;
}
$filename = $sanitized_component . '.php';
$path = realpath( untrailingslashit( BackWPup::get_plugin_data( 'plugindir' ) ) . '/parts/' . $filename );
$allowed_dir = realpath( untrailingslashit( BackWPup::get_plugin_data( 'plugindir' ) ) . '/parts/' );
// If the file doesn't exist and it's a pro version of the plugin, check the pro directory for the component.
if ( ! file_exists( $path ) && BackWPup::is_pro() ) {
$path = realpath( untrailingslashit( BackWPup::get_plugin_data( 'plugindir' ) ) . '/pro/parts/' . $filename );
$allowed_dir = realpath( untrailingslashit( BackWPup::get_plugin_data( 'plugindir' ) ) . '/pro/parts/' );
}
if ( false === $path || false === $allowed_dir ) {
error_log( "Component file not found or outside allowed directory: {$filename}" ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
return null;
}
// Ensure the resolved path is within the allowed components directory, using a directory-boundary-safe check.
$allowed_dir = rtrim( $allowed_dir, DIRECTORY_SEPARATOR );
if ( 0 !== strpos( $path, $allowed_dir . DIRECTORY_SEPARATOR ) ) {
error_log( "Component file not found or outside allowed directory: {$filename}" ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
return null;
}
if ( ! file_exists( $path ) ) {
return;
}
self::$component_path_cache[ 'h:' . $sanitized_component ] = $path;
} else {
$path = self::$component_path_cache[ 'h:' . $sanitized_component ];
}
// Extract the arguments for the component context.
// Avoid overwriting built-in variables.
extract( $args, EXTR_SKIP ); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
// Start output buffering.
ob_start();
include $path; // Execute the PHP file in the local context of extracted arguments.
$output = ob_get_clean();
if ( $return ) {
return $output; // Return the output content for further processing.
}
// Directly echo the content if $return is false (default behavior).
echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
return; //phpcs:ignore Squiz.PHP.NonExecutableCode.ReturnNotRequired
}
/**
* Combines class names into a single string.
*
* @param mixed ...$classes Variable list of class names which can be strings or arrays.
* @return string A space-separated string of class names.
*/
public static function clsx( ...$classes ) {
return implode( ' ', array_filter( $classes ) );
}
/**
* Process backup items.
*
* @param array $items The list of backup items.
* @param array $job_data The job data to merge with each item.
* @param string $dest The destination of the backup.
* @param int $page The current page for pagination.
*
* @return array The processed items.
*/
public static function process_backup_items( array $items, array $job_data, string $dest, int $page ): array {
array_walk(
$items,
function ( &$item ) use ( $job_data, $dest, $page ) {
$item = array_merge( $item, $job_data, [ 'stored_on' => $dest ] );
// Parse the filename to get the type of backup.
$filename = pathinfo( $item['filename'] )['filename'];
if ( stripos( $item['filename'], '.tar.gz' ) === strlen( $item['filename'] ) - 7 ) {
$filename = substr( $item['filename'], 0, -7 );
} elseif ( stripos( $item['filename'], '.tar.bz2' ) === strlen( $item['filename'] ) - 8 ) {
$filename = substr( $item['filename'], 0, -8 );
}
$filename_parts = explode( '_', $filename );
if ( count( $filename_parts ) > 1 ) {
$item['data'] = (array) explode( '-', end( $filename_parts ) );
}
$local_file = untrailingslashit( BackWPup::get_plugin_data( 'TEMP' ) ) . "/{$item['filename']}";
$downloadurl = wp_nonce_url( $item['downloadurl'], 'backwpup_action_nonce' );
$downloadhref = '#TB_inline?height=300&inlineId=tb_download_file&width=640&height=412';
$downloadtrigger = 'download-backup';
// Add the download URL and dataset.
$item['dataset-download'] = [
'data-jobid' => $job_data['id'],
'data-destination' => $dest,
'data-file' => $item['file'],
'data-local-file' => $local_file,
'data-nonce' => wp_create_nonce( 'backwpup_action_nonce' ),
'data-url' => $downloadurl,
'data-href' => $downloadhref,
];
$item['download-trigger'] = $downloadtrigger;
// If the user can restore, add the restore URL.
if ( current_user_can( 'backwpup_restore' ) && ! empty( $item['restoreurl'] ) ) {
$item['dataset-restore'] = [
'label' => __( 'Restore Backup', 'backwpup' ),
'data-url' => wp_nonce_url(
add_query_arg(
[
'step' => 1,
'trigger_download' => 1,
],
$item['restoreurl']
),
'restore-backup_' . $job_data['id']
),
];
} elseif ( current_user_can( 'backwpup_restore' ) ) {
$item['dataset-restore'] = [
'label' => __( 'Restore Backup', 'backwpup' ),
'data-url' => network_admin_url( 'admin.php?page=backwpuprestore' ),
];
}
// If the user can delete, add the delete URL.
if ( current_user_can( 'backwpup_backups_delete' ) ) {
$item['dataset-delete'] = [
'data-url' => wp_nonce_url(
add_query_arg(
[
'page' => 'backwpupbackups',
'action' => 'delete',
'jobdest-top' => $job_data['id'] . '_' . $dest,
'backupfiles[]' => esc_attr( $item['file'] ),
'paged' => $page,
],
network_admin_url( 'admin.php' )
),
'bulk-backups'
),
];
}
}
);
return $items;
}
/***
* Checks if the input string contains path traversal sequences like "..", "../", or "..\".
*
* @param string $input The input string to check.
* @return bool True if the input contains path traversal sequences, false otherwise.
*/
private static function contains_path_traversal( string $input ): bool {
return preg_match( '#(^|[\\\\/])\.\.([\\\\/]|$)#', $input ) === 1;
}
}