Support » Plugin: W3 Total Cache » AWS Connectivity Broken

  • The latest release 0.9.7.5 added in a copy of the AWS SDK and it broke sites that have other plugins using AWS SDK.

    A previous issue posted related to this problem was tagged as resolved when it actually is not resolved. There was a suggestion to add define('W3TC_SKIPLIB_AWS', true); to wp_config but this just eliminates the duplicate SDK load error. If you do add define('W3TC_SKIPLIB_AWS', true); to wp_config then uploads and downloads stop working with the following error log:

    
    [03-Jul-2019 07:09:58 UTC] PHP Fatal error:  Class 'Aws\Credentials\Credentials' not found in /var/www/wp-content/plugins/w3-total-cache/CdnEngine_Mirror_CloudFront.php on line 32
    [03-Jul-2019 07:09:58 UTC] PHP Stack trace:
    [03-Jul-2019 07:09:58 UTC] PHP   1. {main}() /var/www/wp-admin/post.php:0
    [03-Jul-2019 07:09:58 UTC] PHP   2. wp_delete_attachment() /var/www/wp-admin/post.php:303
    [03-Jul-2019 07:09:58 UTC] PHP   3. do_action() /var/www/wp-includes/post.php:5419
    [03-Jul-2019 07:09:58 UTC] PHP   4. WP_Hook->do_action() /var/www/wp-includes/plugin.php:465
    [03-Jul-2019 07:09:58 UTC] PHP   5. WP_Hook->apply_filters() /var/www/wp-includes/class-wp-hook.php:310
    [03-Jul-2019 07:09:58 UTC] PHP   6. call_user_func_array:{/var/www/wp-includes/class-wp-hook.php:286}() /var/www/wp-includes/class-wp-hook.php:286
    [03-Jul-2019 07:09:58 UTC] PHP   7. W3TC\Cdn_Plugin->delete_attachment() /var/www/wp-includes/class-wp-hook.php:286
    [03-Jul-2019 07:09:58 UTC] PHP   8. W3TC\Cdn_Core->purge() /var/www/wp-content/plugins/w3-total-cache/Cdn_Plugin.php:215
    [03-Jul-2019 07:09:58 UTC] PHP   9. W3TC\CdnEngine_Mirror_CloudFront->purge() /var/www/wp-content/plugins/w3-total-cache/Cdn_Core.php:272
    [03-Jul-2019 07:09:58 UTC] PHP  10. W3TC\CdnEngine_Mirror_CloudFront->_init() /var/www/wp-content/plugins/w3-total-cache/CdnEngine_Mirror_CloudFront.php:64
    
    

    Alternate suggestion was to disable other plugins that load the AWS SDK which is not a solution.

    Could you add a field to the W3TC AWS admin to allow us to give you the path for the AWS SDK as previously loaded by the other plugin to use?

    Thanks in advance. We have been using W3TC for 7 years with few issues. This one would be a deal-breaker though. Thanks for all your hard work though. Great plugin 🙂

Viewing 7 replies - 1 through 7 (of 7 total)
  • Plugin Contributor Marko Vasiljevic

    (@vmarko)

    Hello,

    Adding define(‘W3TC_SKIPLIB_AWS’, true); to wp_config it’s a way to make things work if one understands what it does. It’s forcing W3TC not to load own copy but to use the same AWS library code as other projects but other project using AWS library should do the same.
    We tried to limit the number of requests when w3tc loads the AWS library and it happens only when interactions with AWS is required. If other plugins do the same and will not load it always – potentially both products will be able to co-exist.
    Potential conflict with other plugins using the AWS SDK is possible. There are some plugins that were not updated for more than a year and as you can see in this topic => https://wordpress.org/support/topic/cloudfront-cdn-not-working-in-the-latest-update/
    The conflict was resolved just by updating the other plugin to the latest release.

    I’ll speak with the team about your suggestion.

    Thread Starter OnePressTech

    (@timhibberd)

    Cheers Marko.

    The only other plug-in I have installed & active that uses AWS calls is S2Member. XCloner plug-in is installed and uses AWS S3 but it is not activated so there should be no issue there.

    Up until W3TC release 0.9.7.5 S2Member and W3TC have been happily coexisting without issue for the last 7 years on multiple sites I manage. So this is a new issue since the addition to W3TC of the AWS SDK folder / Autoloader. S2Member went dormant for a few years and is just being brought back to life so it is possible there is a version compatibility clash going on.

    I will do further code analysis and debugger analysis tomorrow and update this issue with further details.

    Thanks for your help. Much appreciated. Talk again tomorrow.

    Thread Starter OnePressTech

    (@timhibberd)

    I have tracked this down to some custom secure AWS cookie code in the child theme’s functions.php tied to the init action. It loads its AWS SDK after the W3TC loads its AWS SDK which causes a collision. This functions.php AWS code has happily coexisted with W3TC until release 0.9.7.5 when W3TC upgraded its AWS SDK.

    Adding define(‘W3TC_SKIPLIB_AWS’, true); eliminates the collision but the AWS SDK is loaded by the child theme after the W3TC plugin requires it thus causing a different error as described above.

    I think we both need to adjust our code to call get_included_files to check if the AWS SDK has already been included and only call require_once dirname( __FILE__ ) . '/awssdk/aws-autoloader.php'; if it has NOT been included already.

    I am missing what the value of define('W3TC_SKIPLIB_AWS', true); actually is.

    W3TC can’t rely on a “”only include when needed” model because there may be two plugins that need the AWS SDK loaded on the same page. So W3TC would need to call get_included_files to check if the AWS SDK has already been included and only call require_once dirname( __FILE__ ) . '/awssdk/aws-autoloader.php'; if it has NOT been included already.

    Thoughts?

    Thread Starter OnePressTech

    (@timhibberd)

    I have fixed this issue by adding a conditional wrapper around my call to aws-autoloader.

    if (!class_exists(‘CFCredentials’)){
    require_once dirname( __FILE__ ) . ‘/awssdk/aws-autoloader.php’;
    }

    The issue is that require_once called in different plug-ins may not recognise and ignore the pre-loaded AWS SDK library if the plug-ins do not all use the exact same file naming convention. Require_once appears to only ignore a previously loaded library if it was loaded using the exact same file path (so relative filepaths would be fine but absolute filepaths would not).

    —————————————————————–

    Recommended Action for W3TC:

    I would ask that you consider adjusting the W3TC code to use:

    
        if( !in_array('aws-autoloader.php', get_included_files()) ) {
          require_once W3TC_LIB_DIR . '/Aws/aws-autoloader.php';
        }
    

    OR:

    
        if (!class_exists('CFCredentials')){
          require_once W3TC_LIB_DIR . '/Aws/aws-autoloader.php';
        }
    

    RATHER THAN:

    
        if ( !defined( 'W3TC_SKIPLIB_AWS' ) ) {
    	require_once W3TC_LIB_DIR . '/Aws/aws-autoloader.php';
        }
    

    Thanks for your help. You may mark this as resolved but I would ask that you modify the W3TC code as per recommendation above.

    Thread Starter OnePressTech

    (@timhibberd)

    Update. Leave this issue open. It is not solved.

    I need to load the AWS SDK early in the load sequence because it is used to set encrypted AWS cookies. So W3TC needs to work when the AWS SDK is already loaded by someone else (in this case my AWS cookie code).

    So restating the problem:

    If I set defined( 'W3TC_SKIPLIB_AWS' then I get the error:

    
    [03-Jul-2019 07:09:58 UTC] PHP Fatal error:  Class 'Aws\Credentials\Credentials' not found in /var/www/wp-content/plugins/w3-total-cache/CdnEngine_Mirror_CloudFront.php on line 32
    [03-Jul-2019 07:09:58 UTC] PHP Stack trace:
    [03-Jul-2019 07:09:58 UTC] PHP   1. {main}() /var/www/wp-admin/post.php:0
    [03-Jul-2019 07:09:58 UTC] PHP   2. wp_delete_attachment() /var/www/wp-admin/post.php:303
    [03-Jul-2019 07:09:58 UTC] PHP   3. do_action() /var/www/wp-includes/post.php:5419
    [03-Jul-2019 07:09:58 UTC] PHP   4. WP_Hook->do_action() /var/www/wp-includes/plugin.php:465
    [03-Jul-2019 07:09:58 UTC] PHP   5. WP_Hook->apply_filters() /var/www/wp-includes/class-wp-hook.php:310
    [03-Jul-2019 07:09:58 UTC] PHP   6. call_user_func_array:{/var/www/wp-includes/class-wp-hook.php:286}() /var/www/wp-includes/class-wp-hook.php:286
    [03-Jul-2019 07:09:58 UTC] PHP   7. W3TC\Cdn_Plugin->delete_attachment() /var/www/wp-includes/class-wp-hook.php:286
    [03-Jul-2019 07:09:58 UTC] PHP   8. W3TC\Cdn_Core->purge() /var/www/wp-content/plugins/w3-total-cache/Cdn_Plugin.php:215
    [03-Jul-2019 07:09:58 UTC] PHP   9. W3TC\CdnEngine_Mirror_CloudFront->purge() /var/www/wp-content/plugins/w3-total-cache/Cdn_Core.php:272
    [03-Jul-2019 07:09:58 UTC] PHP  10. W3TC\CdnEngine_Mirror_CloudFront->_init() /var/www/wp-content/plugins/w3-total-cache/CdnEngine_Mirror_CloudFront.php:64
    

    If I don’t set defined( 'W3TC_SKIPLIB_AWS' then I get the error:

    
    [04-Jul-2019 03:17:18 UTC] PHP Fatal error:  Cannot redeclare Aws\constantly() (previously declared in /var/www/wp-content/themes/lixi-elegance/awssdk/Aws/functions.php:19) in /var/www/wp-content/plugins/w3-total-cache/lib/Aws/Aws/functions.php on line 19
    [04-Jul-2019 03:17:18 UTC] PHP Stack trace:
    [04-Jul-2019 03:17:18 UTC] PHP   1. shutdown_action_hook() /var/www/wp-includes/load.php:0
    [04-Jul-2019 03:17:18 UTC] PHP   2. do_action() /var/www/wp-includes/load.php:956
    [04-Jul-2019 03:17:18 UTC] PHP   3. WP_Hook->do_action() /var/www/wp-includes/plugin.php:465
    [04-Jul-2019 03:17:18 UTC] PHP   4. WP_Hook->apply_filters() /var/www/wp-includes/class-wp-hook.php:310
    [04-Jul-2019 03:17:18 UTC] PHP   5. call_user_func_array:{/var/www/wp-includes/class-wp-hook.php:286}() /var/www/wp-includes/class-wp-hook.php:286
    [04-Jul-2019 03:17:18 UTC] PHP   6. wp_ob_end_flush_all() /var/www/wp-includes/class-wp-hook.php:286
    [04-Jul-2019 03:17:18 UTC] PHP   7. ob_end_flush() /var/www/wp-includes/functions.php:4339
    [04-Jul-2019 03:17:18 UTC] PHP   8. W3TC\Generic_Plugin->ob_callback() /var/www/wp-includes/functions.php:4339
    [04-Jul-2019 03:17:18 UTC] PHP   9. apply_filters() /var/www/wp-content/plugins/w3-total-cache/Generic_Plugin.php:535
    [04-Jul-2019 03:17:18 UTC] PHP  10. WP_Hook->apply_filters() /var/www/wp-includes/plugin.php:208
    [04-Jul-2019 03:17:18 UTC] PHP  11. call_user_func_array:{/var/www/wp-includes/class-wp-hook.php:286}() /var/www/wp-includes/class-wp-hook.php:286
    [04-Jul-2019 03:17:18 UTC] PHP  12. W3TC\Cdn_Plugin->w3tc_footer_comment() /var/www/wp-includes/class-wp-hook.php:286
    [04-Jul-2019 03:17:18 UTC] PHP  13. W3TC\Cdn_Core->get_cdn() /var/www/wp-content/plugins/w3-total-cache/Cdn_Plugin.php:812
    [04-Jul-2019 03:17:18 UTC] PHP  14. W3TC\CdnEngine::instance() /var/www/wp-content/plugins/w3-total-cache/Cdn_Core.php:616
    [04-Jul-2019 03:17:18 UTC] PHP  15. spl_autoload_call() /var/www/wp-content/plugins/w3-total-cache/Cdn_Core.php:39
    [04-Jul-2019 03:17:18 UTC] PHP  16. w3tc_class_autoload() /var/www/wp-content/plugins/w3-total-cache/Cdn_Core.php:0
    [04-Jul-2019 03:17:18 UTC] PHP  17. require() /var/www/wp-content/plugins/w3-total-cache/w3-total-cache-api.php:184
    [04-Jul-2019 03:17:18 UTC] PHP  18. require_once() /var/www/wp-content/plugins/w3-total-cache/CdnEngine_Mirror_CloudFront.php:5
    

    Damned if I do…damned if I don’t!

    I will work through the code and try to figure out why WTC AWS fails when the AWS SDK autoloader is skipped. I will update my findings here in this issue.

    Plugin Contributor Marko Vasiljevic

    (@vmarko)

    Hello @timhibberd,

    Thank you for the provided info.

    Thread Starter OnePressTech

    (@timhibberd)

    UPDATE: I have found a fix for this…took a few tries to sort out the problem and an interim solution.

    Problem:
    ——-
    The AWS PHP SDK provided by Amazon has a class autoloader that assumes it is only included once per PHP application. This is problematic for WordPress which consists of independent plug-ins a number of which may include the AWS SDK. One example is W3TC configured to use AWS CloudFront as a CDN.

    At the time of writing the W3TC call to the AWS autoloader is scoped within a W3TC namespace and its call to Aws/Credentials is scoped within multiple classes. This wrecks any chance of standardised re-use of AWS classes among plug-ins and themes since the W3TC copy of the AWS PHP SDK is not public.

    If you try to scope the Aws/Credentials class using the W3TC namespace the AWS SDK class autoloader gets confused. The only solution is to reload the W3TC AWS SDK and rely on the PHP require_once mechanism to allow re-use without reloading. PHP supports multiple reloads of a library located at the same file path but DOES NOT support multiple reloads of a library from different file paths.

    Solution:
    ——–
    Install your AWS SDK in the same directory as your functions that call the AWS SDK functions / classes. The AWS SDK class auto-loader uses __DIR__ to map the AWS classnames to file paths. Additionally, use the following declaration at the top of your file(s) calling the AWS SDK functions / classes.

    if (!class_exists('W3TC\\Config')){
    	require_once __DIR__ . '/Aws/aws-autoloader.php';
    }else{
    	require_once '/var/www/wp-content/plugins/w3-total-cache/lib/Aws/aws-autoloader.php';
    }

    Future:
    ——
    The only way the AWS SDK can be used without loading errors in WordPress is if all plug-ins & themes include the AWS SDK class auto-loader at a global level NOT scoped by a namespace. Until W3TC makes its AWS SDK public the require_once work-around above is necessary.

    In the future, if W3TC DOES make its AWS SDK public, the require-once check described above would need to be adjusted accordingly… e.g. if (!class_exists('Aws')) AND the require-once would use PHP Reflectionclass to programmatically find the filename for the AWS class that is loaded.

    Request to W3TC Devs:
    ———————
    Please consider making your require_once of the AWS SDK public. The conventional WordPress plug-in Namespace hiding technique does not work for the AWS SDK. The AWS SDK class autoloader expects to only be included once for all of WordPress. It can’t be hidden behind a namespace / parent class combo. I thought I could bury my copy of the AWS SDK under my own namespace and class but PHP figured out that there were multiple includes of the same files from different file paths. The alternative would be to fork the AWS SDK and see if we can adjust their class auto-loader (though I am not convinced there is a way around the PHP multi-file include constraints).

    You may choose to close this issue since there is a work-around OR keep it open as a feature request. Your call. I vote for the latter 🙂

    Thanks in advance for your consideration. And thanks for making a great plug-in 🙂

Viewing 7 replies - 1 through 7 (of 7 total)
  • The topic ‘AWS Connectivity Broken’ is closed to new replies.