HEX
Server: nginx/1.28.1
System: Linux iZgw8b5bpgd4jyptfmmmxgZ 6.6.102-5.2.alnx4.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Nov 27 23:11:10 CST 2025 x86_64
User: www (1000)
PHP: 8.2.28
Disabled: passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
Upload Files
File: /www/wwwroot/www.scdc-marine.com/wp-content/plugins/Static-Html-Output/plugin/deployers/S3.php
<?php

class WP2Static_S3 extends WP2Static_SitePublisher {
    public function __construct() {
        $this->loadSettings( 's3' );
        $this->previous_hashes_path = $this->settings[ 'wp_uploads_path' ] . '/WP2STATIC-S3-PREVIOUS-HASHES.txt';
        if ( defined( 'WP_CLI' ) ) {
            return;
        }
        switch ( $_POST[ 'ajax_action' ] ) {
            case 'test_s3': $this->test_s3();
            break;
            case 's3_prepare_export': $this->bootstrap();
            $this->loadArchive();
            $this->prepareDeploy();
            break;
            case 's3_transfer_files': $this->bootstrap();
            $this->loadArchive();
            $this->upload_files();
            break;
            case 'cloudfront_invalidate_all_items': $this->cloudfront_invalidate_all_items();
            break;
        }
    }

    public function upload_files() {
        $this->files_remaining = $this->getRemainingItemsCount();
        if ( $this->files_remaining < 0 ) {
            echo 'ERROR';
            die();
        }
        $this->initiateProgressIndicator();
        $batch_size = $this->settings[ 'deployBatchSize' ];
        if ( $batch_size > $this->files_remaining ) {
            $batch_size = $this->files_remaining;
        }
        $lines = $this->getItemsToDeploy( $batch_size );
        $this->openPreviousHashesFile();
        require_once dirname( __FILE__ ) . '/../WP2Static/MimeTypes.php';
        foreach ( $lines as $line ) {
            list( $local_file, $this->target_path ) = explode( ',', $line );
            $local_file = $this->archive->path . $local_file;
            if ( ! is_file( $local_file ) ) {
                continue;
            }
            if ( isset( $this->settings[ 's3RemotePath' ] ) ) {
                $this->target_path = $this->settings[ 's3RemotePath' ] . '/' . $this->target_path;
            }
            $this->logAction( "Uploading {$local_file} to {$this->target_path} in S3" );
            $this->local_file_contents = file_get_contents( $local_file );
            $this->hash_key = $this->target_path . basename( $local_file );
            if ( isset( $this->file_paths_and_hashes[ $this->hash_key ] ) ) {
                $prev = $this->file_paths_and_hashes[ $this->hash_key ];
                $current = crc32( $this->local_file_contents );
                if ( $prev != $current ) {
                    try {
                        $this->put_s3_object( $this->target_path . basename( $local_file ), $this->local_file_contents, GuessMimeType( $local_file ) );
                    } catch ( Exception $e ) {
                        $this->handleException( $e );
                    }
                } else {
                    $this->logAction( "Skipping {$this->hash_key} as identical " . 'to deploy cache' );
                }
            } else {
                try {
                    $this->put_s3_object( $this->target_path . basename( $local_file ), $this->local_file_contents, GuessMimeType( $local_file ) );
                } catch ( Exception $e ) {
                    $this->handleException( $e );
                }
            }
            $this->recordFilePathAndHashInMemory( $this->hash_key, $this->local_file_contents );
            $this->updateProgress();
        }
        $this->writeFilePathAndHashesToFile();
        $this->pauseBetweenAPICalls();
        if ( $this->uploadsCompleted() ) {
            $this->finalizeDeployment();
        }
    }

    public function test_s3() {
        try {
            $this->put_s3_object( '.tmp_wp2static.txt', 'Test WP2Static connectivity', 'text/plain' );
            if ( ! defined( 'WP_CLI' ) ) {
                echo 'SUCCESS';
            }
        } catch ( Exception $e ) {
            require_once dirname( __FILE__ ) . '/../WP2Static/WsLog.php';
            WsLog::l( 'S3 ERROR RETURNED: ' . $e );
            echo 'There was an error testing S3.\n';
        }
    }

    public function put_s3_object( $s3_path, $content, $content_type ) {
        $s3_path = str_replace( '@', '%40', $s3_path );
        $this->logAction( "PUT'ing file to {$s3_path} in S3" );
        $host_name = $this->settings[ 's3Bucket' ] . '.s3.' . $this->settings[ 's3Region' ] . '.amazonaws.com';
        $this->logAction( "Using S3 Endpoint {$host_name}" );
        $content_acl = 'public-read';
        $content_title = $s3_path;
        $aws_service_name = 's3';
        $timestamp = gmdate( 'Ymd\THis\Z' );
        $date = gmdate( 'Ymd' );
        $request_headers = array();
        $request_headers[ 'Content-Type' ] = $content_type;
        $request_headers[ 'Date' ] = $timestamp;
        $request_headers[ 'Host' ] = $host_name;
        $request_headers[ 'x-amz-acl' ] = $content_acl;
        $request_headers[ 'x-amz-content-sha256' ] = hash( 'sha256', $content );
        ksort( $request_headers );
        $canonical_headers = array();
        foreach ( $request_headers as $key => $value ) {
            $canonical_headers[] = strtolower( $key ) . ':' . $value;
        }
        $canonical_headers = implode( '\n', $canonical_headers );
        $signed_headers = array();
        foreach ( $request_headers as $key => $value ) {
            $signed_headers[] = strtolower( $key );
        }
        $signed_headers = implode( ';', $signed_headers );
        $canonical_request = array();
        $canonical_request[] = 'PUT';
        $canonical_request[] = '/' . $content_title;
        $canonical_request[] = '';
        $canonical_request[] = $canonical_headers;
        $canonical_request[] = '';
        $canonical_request[] = $signed_headers;
        $canonical_request[] = hash( 'sha256', $content );
        $canonical_request = implode( '\n', $canonical_request );
        $hashed_canonical_request = hash( 'sha256', $canonical_request );
        $scope = array();
        $scope[] = $date;
        $scope[] = $this->settings[ 's3Region' ];
        $scope[] = $aws_service_name;
        $scope[] = 'aws4_request';
        $string_to_sign = array();
        $string_to_sign[] = 'AWS4-HMAC-SHA256';
        $string_to_sign[] = $timestamp;
        $string_to_sign[] = implode( '/', $scope );
        $string_to_sign[] = $hashed_canonical_request;
        $string_to_sign = implode( '\n', $string_to_sign );
        $k_secret = 'AWS4' . $this->settings[ 's3Secret' ];
        $k_date = hash_hmac( 'sha256', $date, $k_secret, true );
        $k_region = hash_hmac( 'sha256', $this->settings[ 's3Region' ], $k_date, true );
        $k_service = hash_hmac( 'sha256', $aws_service_name, $k_region, true );
        $k_signing = hash_hmac( 'sha256', 'aws4_request', $k_service, true );
        $signature = hash_hmac( 'sha256', $string_to_sign, $k_signing );
        $authorization = [ 'Credential=' . $this->settings[ 's3Key' ] . '/' . implode( '/', $scope ), 'SignedHeaders=' . $signed_headers, 'Signature=' . $signature, ];
        $authorization = 'AWS4-HMAC-SHA256' . ' ' . implode( ',', $authorization );
        $curl_headers = [ 'Authorization: ' . $authorization ];
        foreach ( $request_headers as $key => $value ) {
            $curl_headers[] = $key . ': ' . $value;
        }
        $url = 'http://' . $host_name . '/' . $content_title;
        $this->logAction( "S3 URL: {$url}" );
        $ch = curl_init( $url );
        curl_setopt( $ch, CURLOPT_HEADER, false );
        curl_setopt( $ch, CURLOPT_HTTPHEADER, $curl_headers );
        curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
        curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 );
        curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
        curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'PUT' );
        curl_setopt( $ch, CURLOPT_USERAGENT, 'WP2Static.com' );
        curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 0 );
        curl_setopt( $ch, CURLOPT_TIMEOUT, 600 );
        curl_setopt( $ch, CURLOPT_POSTFIELDS, $content );
        $output = curl_exec( $ch );
        $http_code = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
        $this->logAction( "API response code: {$http_code}" );
        $this->logAction( "API response body: {$output}" );
        $this->checkForValidResponses( $http_code, array( '200' ) );
        curl_close( $ch );
    }

    public function cloudfront_invalidate_all_items() {
        $this->logAction( 'Invalidating all CloudFront items' );
        if ( ! isset( $this->settings[ 'cfDistributionId' ] ) ) {
            error_log( 'no CF ID found' );
            if ( ! defined( 'WP_CLI' ) ) {
                echo 'SUCCESS';
            }
            return;
        }
        $distribution = $this->settings[ 'cfDistributionId' ];
        $access_key = $this->settings[ 's3Key' ];
        $secret_key = $this->settings[ 's3Secret' ];
        $epoch = date( 'U' );
        $xml = <<<EOD
        <InvalidationBatch>
        <Path>/*</Path>
        <CallerReference> {
            $distribution}
            {
                $epoch}
                </CallerReference>
                </InvalidationBatch>
                EOD;
                $len = strlen( $xml );
                $date = gmdate( 'D, d M Y G:i:s T' );
                $sig = base64_encode( hash_hmac( 'sha1', $date, $secret_key, true ) );
                $msg = 'POST /2010-11-01/distribution/';
                $msg .= "{$distribution}/invalidation HTTP/1.0\r\n";
                $msg .= 'Host: cloudfront.amazonaws.com\r\n';
                $msg .= "Date: {$date}\r\n";
                $msg .= 'Content-Type: text/xml; charset=UTF-8\r\n';
                $msg .= "Authorization: AWS {$access_key}:{$sig}\r\n";
                $msg .= "Content-Length: {$len}\r\n\r\n";
                $msg .= $xml;
                $fp = fsockopen( 'ssl://cloudfront.amazonaws.com', 443, $errno, $errstr, 30 );
                if ( ! $fp ) {
                    require_once dirname( __FILE__ ) . '/../WP2Static/WsLog.php';
                    WsLog::l( "CLOUDFRONT CONNECTION ERROR: {$errno} {$errstr}" );
                    die( "Connection failed: {$errno} {$errstr}\n" );
                }
                fwrite( $fp, $msg );
                $resp = '';
                while ( ! feof( $fp ) ) {
                    $resp .= fgets( $fp, 1024 );
                }
                $this->logAction( "CloudFront response body: {$resp}" );
                fclose( $fp );
                if ( ! defined( 'WP_CLI' ) ) {
                    echo 'SUCCESS';
                }
            }
        }
        $s3 = new WP2Static_S3();