HEX
Server: LiteSpeed
System: Linux server315.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: globfdxw (6114)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: /home/globfdxw/www/wp-content/plugins/wpforms-entry-automation/src/Export/Provider/GoogleDrive.php
<?php

namespace WPFormsEntryAutomation\Export\Provider;

use WPForms\Helpers\File;
use WPFormsEntryAutomation\Export\FormatterManager; // phpcs:ignore WPForms.PHP.UseStatement.UnusedUseStatement
use WPFormsGoogleDrive\Api\Client;
use WPFormsGoogleDrive\Provider\Settings\FormBuilder as GoogleDriveFormBuilder;
use WPFormsGoogleDrive\Api\Http\Request;

/**
 * Google Drive provider implementation.
 *
 * @since 1.0.0
 */
class GoogleDrive extends Provider implements AddonProviderInterface {

	/**
	 * Get a human-readable title of the provider.
	 *
	 * @since 1.0.0
	 *
	 * @return string Provider title.
	 */
	public function get_title(): string {

		return esc_html__( 'Google Drive', 'wpforms-entry-automation' );
	}

	/**
	 * Checks whether the required addon is activated.
	 *
	 * @since 1.0.0
	 *
	 * @return bool True if the addon is activated, false otherwise.
	 */
	public function is_activated(): bool {

		return wpforms_is_addon_initialized( 'google-drive' );
	}

	/**
	 * Retrieve addon data for Dropbox.
	 *
	 * @since 1.0.0
	 *
	 * @return array Addon data for Dropbox.
	 */
	public function get_data(): array {

		return wpforms()->obj( 'addons' )->get_addon( 'google-drive' );
	}

	/**
	 * Retrieve custom templates.
	 *
	 * @since 1.0.0
	 *
	 * @return array List of custom template identifiers.
	 */
	public function get_custom_templates(): array {

		if ( ! $this->is_activated() ) {
			return [];
		}

		return [
			'export-to/google',
			'export-to/google-folder',
		];
	}

	/**
	 * Deliver formatted entries via Google Drive.
	 *
	 * @since 1.0.0
	 *
	 * @param string $entries_file_path Formatted entries.
	 * @param array  $connection        Connection data.
	 * @param array  $form_data         Form data.
	 *
	 * @return bool True on success, false on failure.
	 */
	public function deliver( string $entries_file_path, array $connection, array $form_data ): bool {

		$client = $this->get_api_client( $connection['google']['account_id'] ?? '' );

		if ( ! $client ) {
			wpforms_log(
				'Entry Automation - Google Drive client not found',
				[
					'account_id' => $connection['google']['account_id'] ?? '',
				],
				[
					'type'    => 'error',
					'form_id' => absint( $form_data['id'] ),
				]
			);

			return false;
		}

		// Get Google Drive settings.
		$request_args = $this->get_request_args( $entries_file_path, $connection );

		// Upload a file to Google Drive.
		$file_id = $client->upload_file( $request_args );

		wpforms_entry_automation()->get( 'tasks' )->update(
			$connection['task_id'],
			[
				'destination' => $file_id,
				'file'        => $request_args['name'],
			]
		);

		if ( empty( $file_id ) ) {
			wpforms_log(
				'Entry Automation - Google Drive upload failed',
				[
					'file_id' => $file_id,
					'file'    => $request_args['name'],
				],
				[
					'type'    => 'error',
					'form_id' => absint( $form_data['id'] ),
				]
			);
		}

		return ! empty( $file_id );
	}

	/**
	 * Checks if a file exists on Google Drive using the provided file ID and connection details.
	 *
	 * @since 1.0.0
	 *
	 * @param string $file_name  The name of the file to check for existence.
	 * @param array  $task_data  An associative array containing task-specific data, including the file ID.
	 * @param array  $connection An associative array containing connection details, including the Google account ID.
	 *
	 * @return bool Returns true if the file exists, otherwise false.
	 */
	public function is_file_exist( string $file_name, array $task_data, array $connection ): bool {

		$file_id = $task_data['destination'] ?? '';

		// If the file_id is empty, return false immediately.
		if ( empty( $file_id ) ) {
			return false;
		}

		// Get the client using the account ID from task data.
		$client = $this->get_api_client( $connection['google']['account_id'] ?? '' );

		if ( ! $client ) {
			return false;
		}

		// Create a Request object with the client's access token.
		$request = new Request( $client->get_access_token() );

		// Construct the API URL to get file metadata.
		$url = 'https://www.googleapis.com/drive/v3/files/' . $file_id;

		// Send a GET request to check if the file exists.
		$response = $request->get( $url, [ 'fields' => 'id,name' ] );

		// Return true if the file exists.
		return ! $response->has_errors();
	}

	/**
	 * Downloads a file from Google Drive using the provided file ID and connection details.
	 *
	 * @since 1.0.0
	 *
	 * @param array $task_data  An associative array containing task-specific data used during the download operation.
	 * @param array $connection An associative array containing connection details, including the Google account ID.
	 *
	 * @return string The path to the downloaded temporary file if successful, or an empty string on failure.
	 */
	public function download_file( array $task_data, array $connection ): string {

		$file_id = $task_data['destination'] ?? '';

		if ( empty( $file_id ) ) {
			return '';
		}

		$client = $this->get_api_client( $connection['google']['account_id'] ?? '' );

		if ( ! $client ) {
			return '';
		}

		// Create a Request object with the client's access token.
		$request = new Request( $client->get_access_token() );

		// Construct the API URL for the file download.
		$url = 'https://www.googleapis.com/drive/v3/files/' . $file_id;

		// Send a GET request to download the file content.
		$response = $request->get( $url, [ 'alt' => 'media' ] );

		// Here we should abort the process or continue uploading the regular file.
		if ( $response->has_errors() ) {
			return '';
		}

		/**
		 * Formatter manager instance.
		 *
		 * @var FormatterManager $formatter_manager
		 */
		$formatter_manager = wpforms_entry_automation()->get( 'formatter_manager' );
		// Create a temporary file to store the downloaded content.
		$tmp_file = $formatter_manager->get_temp_dir() . '/' . $task_data['file_name'];
		// Write the file content to the temporary file.
		$content = $response->get_file();
		$result  = File::put_contents( $tmp_file, $content );

		return $result === false ? '' : $tmp_file;
	}

	/**
	 * Deletes a file from Google Drive using the provided file ID and connection details.
	 *
	 * @since 1.0.0
	 *
	 * @param array $task_data  An associative array containing task-specific data used during the delete operation.
	 * @param array $connection An associative array containing connection details, including the Google account ID.
	 */
	public function delete_file( array $task_data, array $connection ): void {

		$file_id = $task_data['destination'] ?? '';

		if ( empty( $file_id ) ) {
			return;
		}

		$client = $this->get_api_client( $connection['google']['account_id'] ?? '' );

		if ( ! $client ) {
			return;
		}

		// Create a Request object with the client's access token.
		$request = new Request( $client->get_access_token() );
		// Send a DELETE request to the API to delete the file.
		// It's okay, even if it fails.
		$request->delete(
			'https://www.googleapis.com/drive/v3/files/' . $file_id
		);
	}

	/**
	 * Sanitizes connection data for export destinations and processes Google connection specifics if applicable.
	 *
	 * @since 1.0.0
	 *
	 * @param array &$connection_data An associative array representing the connection data to be sanitized. It may be updated during the process.
	 * @param array $form_data        An associative array containing form data related to the connection.
	 */
	public function sanitize_connection( array &$connection_data, array $form_data ): void {

		$connection_data['google']               = $connection_data['google'] ?? [];
		$connection_data['google']['account_id'] = sanitize_text_field( $connection_data['google']['account_id'] ?? '' );

		$this->sanitize_folder( $connection_data );
		$this->create_folder( $connection_data, $form_data );
	}

	/**
	 * Sanitizes folder-related data within the provided connection data array.
	 * Adjusts and validates the folder type and appropriately sanitizes or removes folder-specific fields.
	 *
	 * @since 1.0.0
	 *
	 * @param array &$connection_data An associative array containing Google connection data.
	 *                                Includes folder settings that will be sanitized and updated.
	 */
	private function sanitize_folder( array &$connection_data ): void {

		$folder_type = $connection_data['google']['folder_type'] ?? '';
		$folder_type = in_array( $folder_type, [ 'new', 'existing' ], true ) ? $folder_type : 'new';

		$connection_data['google']['folder_type'] = $folder_type;

		if ( $folder_type === 'new' ) {
			$connection_data['google']['folder_name'] = sanitize_text_field( $connection_data['google']['folder_name'] ?? '' );

			unset( $connection_data['google']['folder_id'] );
		} else {
			$connection_data['google']['folder_id'] = sanitize_text_field( $connection_data['google']['folder_id'] ?? '' );

			unset( $connection_data['google']['folder_name'] );
		}
	}

	/**
	 * Create a folder in Google Drive.
	 *
	 * @since 1.0.0
	 *
	 * @param array &$connection_data Google Drive connection data.
	 * @param array $form_data        Form data used to generate the folder.
	 */
	public function create_folder( array &$connection_data, array $form_data ): void {

		$google_form_builder = $this->get_google_drive_form_builder();
		$google              = $connection_data['google'] ?? [];
		$export_to           = $connection_data['export_to'] ?? '';

		if (
			! $google_form_builder ||
			$export_to !== 'google' ||
			(
				! empty( $google['folder_type'] ) &&
				$google['folder_type'] !== 'new'
			)
		) {
			return;
		}

		$google_form_builder->create_folder( $google, $form_data );
		$connection_data['google'] = $google;
	}

	/**
	 * Retrieve the Google Drive form builder instance.
	 *
	 * This method attempts to fetch the form builder instance for Google Drive integration
	 * if the associated function exists.
	 *
	 * @since 1.0.0
	 *
	 * @return GoogleDriveFormBuilder|null The Google Drive form builder instance or null if not available.
	 */
	private function get_google_drive_form_builder(): ?GoogleDriveFormBuilder {

		if ( ! $this->is_activated() ) {
			return null;
		}

		return wpforms_google_drive()->get( 'core' )->get_form_builder();
	}

	/**
	 * Build and retrieve request arguments.
	 *
	 * @since 1.0.0
	 *
	 * @param string $entries_file_path Path to the entries file.
	 * @param array  $connection        Connection configuration array.
	 *
	 * @return array List of request arguments.
	 */
	private function get_request_args( string $entries_file_path, array $connection ): array {

		// FileInfo PHP extension (ext-fileinfo) is safely loaded by the Google Drive addon.
		$mime_type = mime_content_type( $entries_file_path );
		$extension = strtolower( pathinfo( $entries_file_path, PATHINFO_EXTENSION ) );

		if ( $mime_type === 'text/plain' && $extension === 'csv' ) {
			$mime_type = 'application/csv';
		}

		return [
			'name'      => basename( $entries_file_path ),
			'path'      => $entries_file_path,
			'mime'      => $mime_type,
			'folder_id' => $connection['google']['folder_id'] ?? '',
		];
	}

	/**
	 * Retrieve an API client for the provided account ID.
	 *
	 * @since 1.0.0
	 *
	 * @param string $account_id The account ID for which the API client is to be retrieved.
	 *
	 * @return Client|null The API client instance if available, or null if not found.
	 */
	private function get_api_client( string $account_id ): ?Client {

		if ( ! $this->is_activated() ) {
			return null;
		}

		$account = wpforms_google_drive()->get( 'account' );

		if ( ! $account ) {
			return null;
		}

		return $account->get_client_by_id( $account_id );
	}
}