Guenni007 icon

class-avia-instagram

Guenni007 | PRO | 07/03/26 03:41:07 PM UTC (Edited) | 1 ⭐ | 7805 👁️ | Never ⏰ | []
PHP |

46.98 KB

|

None

|

1 👍

/

0 👎

<?php
namespace aviaFramework\widgets;
 
use \WP_Error;
use \AviaHelper;
 
/**
 * AVIA INSTAGRAM WIDGET
 *
 * Widget that displays your latest Instagram Photos
 *
 * Modified version - SECURITY HARDENED
 * =====================================
 *
 * Adds a background caching of images on own server to avoid to access instagram to display the images
 *
 * Security fixes applied (vs. original):
 * 1. sslverify no longer disabled when contacting instagram.com (MITM protection)
 * 2. Host allowlist enforced before downloading any URL returned by instagram (SSRF protection)
 * 3. Downloaded files are validated as real images (wp_check_filetype + getimagesize) before being kept
 * 4. File permissions reduced from 0777 to 0644
 * 5. Filenames are run through sanitize_file_name() instead of using raw basename() from remote data
 * 6. download_url() calls are given an explicit timeout and downloaded files are size-checked
 *
 * @package AviaFramework
 * @since ???
 * @since 4.3.1         extended, improved and modified by günter
 * @since 4.9           Code was moved from class-framework-widgets.php
 * @since 4.3.1-secure  hardened by Guenni007 - see notes above
 */
if( ! defined( 'AVIA_FW' ) ) {  exit( 'No direct script access allowed' );  }
 
 
if( ! class_exists( __NAMESPACE__ . '\avia_instagram_widget', false ) )
{
    class avia_instagram_widget extends \aviaFramework\widgets\base\Avia_Widget
    {
        /**
         * @since 4.3.1
         * @var array
         */
        protected $upload_folders;
 
        /**
         * Stores the expire time for cached images in seconds.
         *
         * @since 4.3.1
         * @var int
         */
        protected $expire_time;
 
        /**
         * @since 4.3.1
         * @var boolean
         */
        protected $activate_cron;
 
        /**
         * Holds all caching info for each widget instance.
         *
         * @since 4.3.1
         * @var array
         */
        protected $cache;
 
        /**
         * @since 4.3.1
         * @var array
         */
        protected $cached_file_sizes;
 
        /**
         * Allowed remote hosts for image downloads (SSRF protection).
         * Instagram/Meta serves media from these CDN domains. Anything else is rejected.
         *
         * @since 4.3.1-secure
         * @var array
         */
        protected $allowed_download_hosts;
 
        /**
         * Allowed mime types for cached image files.
         *
         * @since 4.3.1-secure
         * @var array
         */
        protected $allowed_mime_types;
 
        /**
         * Maximum accepted file size (bytes) for a single downloaded image.
         *
         * @since 4.3.1-secure
         * @var int
         */
        protected $max_file_size;
 
        public function __construct()
        {
            $id_base = 'avia-instagram-feed';
            $name = THEMENAME . ' ' . __( 'Instagram', 'avia_framework' );
 
            $widget_options = array(
                            'classname'             => 'avia-instagram-feed avia_no_block_preview',
                            'description'           => __( 'Displays your latest Instagram photos', 'avia_framework' ),
                            'show_instance_in_rest' => true,
                            'customize_selective_refresh' => false
                        );
 
            parent::__construct( $id_base, $name, $widget_options );
 
            $this->defaults = array(
                                'title'         => __( 'Instagram', 'avia_framework' ),
                                'username'      => '',
                                'cache'         => apply_filters( 'avf_instagram_default_cache_location', '' ),     //  '' | 'server'
                                'number'        => 9,
                                'columns'       => 3,
                                'size'          => 'thumbnail',
                                'target'        => 'lightbox' ,
                                'link'          => __( 'Follow Me!', 'avia_framework' ),
                                'avia_key'      => ''
                            );
 
            $this->upload_folders = wp_upload_dir();
 
            if( is_ssl() )
            {
                $this->upload_folders['baseurl'] = str_replace( 'http://', 'https://', $this->upload_folders['baseurl'] );
            }
 
            $folder = apply_filters( 'avf_instagram_cache_folder_name', 'avia_instagram_cache' );
 
            $this->upload_folders['instagram_dir'] = trailingslashit( trailingslashit( $this->upload_folders['basedir'] ) . $folder );
            $this->upload_folders['instagram_url'] = trailingslashit( trailingslashit( $this->upload_folders['baseurl'] ) . $folder );
 
            $this->expire_time = HOUR_IN_SECONDS * 2;
 
            $this->expire_time = apply_filters_deprecated( 'null_instagram_cache_time', array( $this->expire_time ), '4.3.1', 'avf_instagram_file_cache_time', __( 'Adding possible file caching on server might need a longer period of time to invalidate cache.', 'avia_framework' ) );
            $this->expire_time = apply_filters( 'avf_instagram_file_cache_time', $this->expire_time );
 
            $this->activate_cron = ! ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON );
            $this->activate_cron = apply_filters( 'avf_instagram_activate_cron', $this->activate_cron );
 
            $this->cache = $this->get_cache();
 
            $this->cached_file_sizes = array( 'thumbnail', 'small', 'large', 'original' );
 
            /**
             * SECURITY: only these hosts may ever be contacted for a media download.
             * Adjust via filter if Meta/Instagram changes their CDN domains.
             *
             * @since 4.3.1-secure
             */
            $this->allowed_download_hosts = apply_filters( 'avf_instagram_allowed_download_hosts', array(
                    'cdninstagram.com',
                    'fbcdn.net',
                ) );
 
            /**
             * SECURITY: only these mime types are accepted for cached files.
             *
             * @since 4.3.1-secure
             */
            $this->allowed_mime_types = apply_filters( 'avf_instagram_allowed_mime_types', array(
                    'jpg|jpeg|jpe' => 'image/jpeg',
                    'png'          => 'image/png',
                    'webp'         => 'image/webp',
                ) );
 
            /**
             * SECURITY: reject anything larger than this (default 15 MB) - avoids disk-fill / DoS via
             * an attacker-controlled or compromised response serving an oversized payload.
             *
             * @since 4.3.1-secure
             */
            $this->max_file_size = apply_filters( 'avf_instagram_max_file_size', 15 * MB_IN_BYTES );
 
            /**
             * WP Cron job events
             */
            if( $this->activate_cron )
            {
                add_action( 'av_instagram_scheduled_filecheck', array( $this, 'handler_scheduled_filecheck' ), 10 );
            }
 
            /**
             * Makes sure to keep cron job alive as fallback
             */
            if( is_admin() )
            {
                add_action( 'admin_init', array( $this, 'handler_init_filecheck' ), 99999 );
                add_action( 'delete_widget', array( $this, 'handler_delete_widget' ), 10, 3 );
            }
            else
            {
                add_action( 'init', array( $this, 'handler_init_filecheck' ), 99999 );
            }
 
        }
 
        /**
         * @since 4.3.1
         */
        public function __destruct()
        {
            parent::__destruct();
 
            unset( $this->upload_folders );
            unset( $this->cache );
            unset( $this->cached_file_sizes );
        }
 
        /**
         * Returns the cache info array
         *
         * @since 4.3.1
         * @return array
         */
        public function get_cache()
        {
            if( is_null( $this->cache ) )
            {
                $cache = get_option( 'avia_instagram_widgets_cache', '' );
 
                if( is_array( $cache ) )
                {
                    $this->cache = $cache;
                }
                else if( ! is_string( $cache ) || empty( $cache ) )
                {
                    $this->cache = null;
                }
                else
                {
                    $cache = json_decode( $cache, true );
                    $this->cache = is_array( $cache ) ? $cache : null;
                }
 
                if( empty( $this->cache ) )
                {
                    $this->cache = array(
                            'last_updated'      => 0,
                            'instances'         => array()
                        );
                }
            }
 
            return $this->cache;
        }
 
        /**
         * Update the cache array in DB
         *
         * @since 4.3.1
         * @param array|null $cache
         */
        public function update_cache( ?array $cache = null )
        {
            if( ! is_null( $cache) )
            {
                $this->cache = $cache;
            }
 
            $save = json_encode( $this->cache );
            update_option( 'avia_instagram_widgets_cache', $save );
        }
 
        /**
         * Ensure a valid instance array filled with defaults
         *
         * @since 4.3.1
         * @param array $instance_cache
         * @return array
         */
        protected function parse_args_instance_cache( array $instance_cache )
        {
            $instance_cache = wp_parse_args( (array) $instance_cache, array(
                                            'upload_folder'     => '',
                                            'path_error'        => '',
                                            'instagram_error'   => '',
                                            'upload_errors'     => false,
                                            'last_update'       => 0,
                                            'cached_list'       => array(),
                                            'instagram_list'    => array()
                                        ));
 
            return $instance_cache;
        }
 
        /**
         * Creates a unique key for the given instance for our cache array
         *
         * @since 4.3.1
         * @param array $instance
         * @param string $id_widget
         * @return string
         */
        protected function create_avia_key( array $instance, $id_widget )
        {
            $k = 0;
            $key = str_replace( $this->id_base . '-', '', $id_widget ) . '-' . AviaHelper::save_string( $instance['title'], '-' );
 
            $orig_key = $key;
            while( array_key_exists( $key, $this->cache['instances'] ) )
            {
                $key = $orig_key . "-{$k}";
                $k++;
            }
 
            return $key;
        }
 
        /**
         * Output the widget in frontend
         *
         * NOTE: rendering logic (widget/form/update/block preview) is unchanged from the
         * original - the security issues in the original were all in the data-fetching /
         * file-caching layer below, not in output escaping, which already looked correct.
         *
         * @param array $args
         * @param array $instance
         */
        public function widget( $args, $instance )
        {
            $instance = $this->parse_args_instance( $instance );
 
            $fields = $this->get_field_names();
 
            foreach( $instance as $key => $value )
            {
                if( in_array( $key, $fields ) )
                {
                    $instance[ $key ] = esc_attr( $value );
                }
            }
 
            $instance = apply_filters( 'avf_widget_front_instance', $instance, $args, get_called_class() );
 
            if( $this->in_block_editor_preview( $args, $instance ) )
            {
                return;
            }
 
            extract( $args, EXTR_SKIP );
            extract( $instance, EXTR_SKIP );
 
            $original_cache = $cache;
            $cache = apply_filters( 'avf_conditional_setting_external_links', $cache, __CLASS__, $this, $args, $instance );
            if( ! in_array( $cache, array( '', 'server' ) ) )
            {
               $cache = $original_cache;
            }
 
            $title = apply_filters( 'widget_title', $title, $args );
 
            if( ( trim( $username ) == '' ) && ! is_user_logged_in() && ! current_user_can( 'edit_posts' ) )
            {
                return;
            }
 
            echo $before_widget;
 
            if ( ! empty( $title ) )
            {
                echo $before_title . $title . $after_title;
            }
 
            do_action( 'aviw_before_widget', $instance );
 
            if( $username != '' )
            {
                $errors = array();
                $media_array = array();
 
                $instance_cache = isset( $this->cache['instances'][ $instance['avia_key'] ] ) ? $this->cache['instances'][ $instance['avia_key'] ] : null;
 
                if( ! is_null( $instance_cache ) )
                {
                    if( ! empty( $instance_cache['instagram_error'] ) )
                    {
                        $errors =  array( $instance_cache['instagram_error'] );
                    }
                    if( ! empty( $instance_cache['upload_errors'] ) && ( 'server' == $instance['cache'] ) )
                    {
                        foreach( $instance_cache['cached_list'] as $img )
                        {
                            if( ! empty( $img['errors'] ) )
                            {
                                $errors = array_merge( $errors, $img['errors'] );
                            }
                        }
                    }
 
                    if( 'server' == $instance['cache'] )
                    {
                        $media_array = $instance_cache['cached_list'];
 
                        $url = trailingslashit( trailingslashit( $this->upload_folders['instagram_url'] ) . $instance_cache['upload_folder'] );
 
                        foreach( $media_array as $key => $media )
                        {
                            if( ! empty( $media['errors'] ) )
                            {
                                $errors = array_merge( $errors, $media['errors'] );
                            }
 
                            if( ! empty( $media[ $size ] ) )
                            {
                                $media_array[ $key ][ $size ] = $url . $media[ $size ];
                            }
                            if( ! empty( $media[ 'original' ] ) )
                            {
                                $media_array[ $key ]['original'] = $url . $media['original'];
                            }
                        }
                    }
                    else
                    {
                        $media_array = $instance_cache['instagram_list'];
                    }
                }
 
                if( ! empty( $errors ) && is_user_logged_in() && current_user_can( 'edit_posts' ) )
                {
                    $errors = array_map( 'esc_html__', $errors );
 
                    $out = '';
                    $out .= '<div class="av-instagram-errors">';
                    $out .=     '<p class="av-instagram-errors-msg av-instagram-admin">' . esc_html__( 'Only visible for admins:', 'avia_framework' ) . '</p>';
                    $out .=     '<p class="av-instagram-errors-msg av-instagram-admin">';
                    $out .=         implode( '<br />', $errors );
                    $out .=     '</p>';
                    $out .= '</div>';
 
                    echo $out;
                }
 
                if( count( $media_array ) > 0 )
                {
                    $ulclass = esc_attr( apply_filters( 'aviw_list_class', 'av-instagram-pics av-instagram-size-' . $size ) );
                    $rowclass = esc_attr( apply_filters( 'aviw_row_class', 'av-instagram-row' ) );
                    $liclass = esc_attr( apply_filters( 'aviw_item_class', 'av-instagram-item' ) );
                    $aclass = esc_attr( apply_filters( 'aviw_a_class', '' ) );
                    $imgclass = esc_attr( apply_filters( 'aviw_img_class', '' ) );
 
                    echo '<div class="' . esc_attr( $ulclass ) . '">';
 
                    $last_id = end( $media_array );
                    $last_id = $last_id['id'];
 
                    $rowcount = 0;
                    $itemcount = 0;
                    foreach ( $media_array as $item )
                    {
                        if( empty( $item[ $size ] ) )
                        {
                            continue;
                        }
 
                        if( $rowcount == 0 )
                        {
                            echo "<div class='{$rowclass}'>";
                        }
 
                        $rowcount ++;
                        $itemcount ++;
 
                        $targeting = $target;
                        if( $target == "lightbox" )
                        {
                            $targeting = "";
                            $item['link'] = ! empty( $item['original'] ) ? $item['original'] : $item[ $size ];
                        }
 
                        echo '<div class="' . $liclass . '">';
                        echo    '<a href="' . esc_url( $item['link'] ) . '" target="' . esc_attr( $targeting ) . '"  class="' . $aclass . ' ' . $imgclass . '" title="' . esc_attr( $item['description'] ) . '" style="background-image:url(' . esc_url( $item[ $size ] ) . ');">';
                        echo    '</a>';
                        echo '</div>';
 
                        if( $rowcount % $columns == 0 || $last_id == $item['id'] || ( $itemcount >= $number ) )
                        {
                            echo '</div>';
                            $rowcount = 0;
 
                            if( $itemcount >= $number )
                            {
                                break;
                            }
                        }
                    }
                    echo '</div>';
                }
                else
                {
                    echo '<p class="av-instagram-errors-msg">' . esc_html__( 'No images available at the moment', 'avia_framework' ) . '</p>';
                }
            }
            else
            {
                echo '<p class="av-instagram-errors-msg av-instagram-admin">' . esc_html__( 'For admins only: Missing Instagram user name !!', 'avia_framework' ) . '</p>';
            }
 
            if ( $link != '' )
            {
                echo '<a class="av-instagram-follow avia-button" href="https://instagram.com/' . esc_attr( trim( $username ) ) . '" rel="me" target="' . esc_attr( $target ) . '">' . $link . '</a>';
            }
 
            do_action( 'aviw_after_widget', $instance );
 
            echo $after_widget;
        }
 
        /**
         * Callback to output a custom block preview
         *
         * @since 4.9
         * @param array $args
         * @param array $instance
         * @return boolean
         */
        protected function widget_block_preview( array $args, array $instance = array() )
        {
            echo isset( $args['before_widget'] ) ? $args['before_widget'] : '';
 
            echo '<div class="avia-preview-headline">' . $this->name . '</div>';
            echo '<div class="avia-preview-info">' . __( 'Title:', 'avia_framework' ) . ' ' . esc_html( $instance['title'] ) .  '</div>';
            echo '<div class="avia-preview-info">' . __( 'Username:', 'avia_framework' ) . ' ' . esc_html( $instance['username'] ) .  '</div>';
            echo '<div class="avia-preview-in-front">' . __( 'Content is only rendered in frontend.', 'avia_framework' ) . '</div>';
 
            echo isset( $args['after_widget'] ) ? $args['after_widget'] : '';
 
            return true;
        }
 
        /**
         * Output the form in backend
         *
         * @param array $instance
         */
        public function form( $instance )
        {
            $instance = $this->parse_args_instance( $instance );
            $fields = $this->get_field_names();
 
            foreach( $instance as $key => $value )
            {
                if( in_array( $key, $fields ) )
                {
                    switch( $key )
                    {
                        case 'number':
                        case 'columns':
                            $instance[ $key ] = absint( $value );
                            break;
                        default:
                            $instance[ $key ] = esc_attr( $value );
                            break;
                    }
                }
            }
 
            extract( $instance );
 
            ?>
            <p><label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title', 'avia_framework' ); ?>: <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" /></label></p>
            <p><label for="<?php echo $this->get_field_id( 'username' ); ?>"><?php _e( 'Username', 'avia_framework' ); ?>: <input class="widefat" id="<?php echo $this->get_field_id( 'username' ); ?>" name="<?php echo $this->get_field_name( 'username' ); ?>" type="text" value="<?php echo esc_attr( $username ); ?>" /></label></p>
            <p><label for="<?php echo $this->get_field_id( 'cache' ); ?>"><?php _e( 'Location of your photos or videos', 'avia_framework' ); ?>:</label>
                <select id="<?php echo $this->get_field_id( 'cache' ); ?>" name="<?php echo $this->get_field_name( 'cache' ); ?>" class="widefat">
                    <option value="" <?php selected( '', $cache ) ?>><?php _e( 'Get from your instagram account (instagram server connection needed)', 'avia_framework' ); ?></option>
                    <option value="server" <?php selected( 'server', $cache ) ?>><?php _e( 'Cache on your server - no instagram connection needed on pageload', 'avia_framework' ); ?></option>
                </select>
            </p>
            <p><label for="<?php echo $this->get_field_id( 'number' ); ?>"><?php _e( 'Number of photos', 'avia_framework' ); ?>:</label>
                <select id="<?php echo $this->get_field_id( 'number' ); ?>" name="<?php echo $this->get_field_name( 'number' ); ?>" class="widefat">
                    <?php for( $i = 1; $i <= 12; $i++ ) : ?>
                    <option value="<?php echo $i; ?>" <?php selected( $i, $number ) ?>><?php echo $i; ?></option>
                    <?php endfor; ?>
                </select>
            </p>
            <p><label for="<?php echo $this->get_field_id( 'columns' ); ?>"><?php _e( 'Number of columns', 'avia_framework' ); ?>:</label>
                <select id="<?php echo $this->get_field_id( 'columns' ); ?>" name="<?php echo $this->get_field_name( 'columns' ); ?>" class="widefat">
                    <?php for( $i = 1; $i <= 6; $i++ ) : ?>
                    <option value="<?php echo $i; ?>" <?php selected( $i, $columns ) ?>><?php echo $i; ?></option>
                    <?php endfor; ?>
                </select>
            </p>
            <p><label for="<?php echo $this->get_field_id( 'size' ); ?>"><?php _e( 'Thumbnail size', 'avia_framework' ); ?>:</label>
                <select id="<?php echo $this->get_field_id( 'size' ); ?>" name="<?php echo $this->get_field_name( 'size' ); ?>" class="widefat">
                    <option value="thumbnail" <?php selected( 'thumbnail', $size ) ?>><?php _e( 'Thumbnail', 'avia_framework' ); ?></option>
                    <option value="small" <?php selected( 'small', $size ) ?>><?php _e( 'Small', 'avia_framework' ); ?></option>
                    <option value="large" <?php selected( 'large', $size ) ?>><?php _e( 'Large', 'avia_framework' ); ?></option>
                    <option value="original" <?php selected( 'original', $size ) ?>><?php _e( 'Original', 'avia_framework' ); ?></option>
                </select>
            </p>
            <p><label for="<?php echo $this->get_field_id( 'target' ); ?>"><?php _e( 'Open links in', 'avia_framework' ); ?>:</label>
                <select id="<?php echo $this->get_field_id( 'target' ); ?>" name="<?php echo $this->get_field_name( 'target' ); ?>" class="widefat">
                    <option value="lightbox" <?php selected( 'lightbox', $target ) ?>><?php _e( 'Lightbox', 'avia_framework' ); ?></option>
                    <option value="_self" <?php selected( '_self', $target ) ?>><?php _e( 'Current window (_self)', 'avia_framework' ); ?></option>
                    <option value="_blank" <?php selected( '_blank', $target ) ?>><?php _e( 'New window (_blank)', 'avia_framework' ); ?></option>
                </select>
            </p>
            <p><label for="<?php echo $this->get_field_id( 'link' ); ?>"><?php _e( 'Link text', 'avia_framework' ); ?>: <input class="widefat" id="<?php echo $this->get_field_id( 'link' ); ?>" name="<?php echo $this->get_field_name( 'link' ); ?>" type="text" value="<?php echo esc_attr( $link ); ?>" /></label></p>
 
            <?php
 
            if( ! $this->activate_cron )
            {
                echo '<p class="av-instagram-no-cron">';
                echo    __( 'WP Cron jobs are disabled. To assure a regular update of cached data and an optimal pageload in frontend and backend we recommend to activate this.', 'avia_framework' );
                echo '</p>';
 
                $timestamp = ( $this->cache['last_updated'] != 0 ) ? $this->cache['last_updated'] + $this->expire_time : false;
                $time = ( false !== $timestamp ) ? date( 'Y/m/d H:i a', $timestamp ) .  __( ' UTC', 'avia_framework' ) : __( 'No time available', 'avia_framework' );
 
                echo '<p class="av-instagram-next-update">';
                echo    __( 'The widget preloads and caches Instagram data for better performance.', 'avia_framework' )." ";
                echo    sprintf( __( 'Next update: %s', 'avia_framework' ), $time );
                echo '</p>';
            }
            else
            {
                $timestamp = wp_next_scheduled( 'av_instagram_scheduled_filecheck' );
                $time = ( false !== $timestamp ) ? date( "Y/m/d H:i", $timestamp ) .  __( ' UTC', 'avia_framework' ) : __( 'No time available', 'avia_framework' );
 
                echo '<p class="av-instagram-next-update">';
                echo    __( 'The widget preloads and caches Instagram data for better performance.', 'avia_framework' )." ";
                echo    sprintf( __( 'Next update: %s', 'avia_framework' ), $time );
                echo '</p>';
            }
 
            if( empty( $instance['avia_key'] ) )
            {
                return;
            }
 
            if( empty( $this->cache['instances'][ $instance['avia_key'] ] ) )
            {
                return;
            }
 
            $instance_cache = $this->cache['instances'][ $instance['avia_key'] ];
            $errors = array();
 
            if( ! empty( $instance_cache['instagram_error'] ) )
            {
                $errors = (array) $instance_cache['instagram_error'];
            }
 
            if( 'server' == $instance['cache'] )
            {
                foreach( $instance_cache['cached_list'] as $image )
                {
                    if( ! empty( $image['errors'] ) )
                    {
                        $errors = array_merge( $errors, $image['errors'] );
                    }
                }
            }
 
            if( ! empty( $errors ) )
            {
                $errors = array_map( 'esc_html__', $errors );
 
                $out  = '<div class="av-instagram-errors">';
                $out .=     '<p class="av-instagram-errors-msg av-instagram-error-headline">' . esc_html__( 'Errors found:', 'avia_framework' ) . '</p>';
                $out .=     '<p class="av-instagram-errors-msg">';
                $out .=         implode( '<br />', $errors );
                $out .=     '</p>';
                $out .= '</div>';
 
                echo $out;
            }
 
        }
 
        /**
         * Update widget options
         *
         * @param array $new_instance
         * @param array $old_instance
         * @return array
         */
        public function update( $new_instance, $old_instance )
        {
            $instance = $this->parse_args_instance( $old_instance );
 
            $instance['title'] = strip_tags( $new_instance['title'] );
            $instance['username'] = trim( strip_tags( $new_instance['username'] ) );
            $instance['cache'] = ( $new_instance['cache'] == 'server' || $new_instance['cache'] == '' ) ? $new_instance['cache'] : apply_filters( 'avf_instagram_default_cache_location', 'server' );
            $instance['number'] = ! absint( $new_instance['number'] ) ? 9 : $new_instance['number'];
            $instance['columns'] = ! absint( $new_instance['columns'] ) ? 3 : $new_instance['columns'];
            $instance['size'] = ( $new_instance['size'] == 'thumbnail' || $new_instance['size'] == 'large' || $new_instance['size'] == 'small' || $new_instance['size'] == 'original' ) ? $new_instance['size'] : 'large';
            $instance['target'] = ( $new_instance['target'] == '_self' || $new_instance['target'] == '_blank'|| $new_instance['target'] == 'lightbox' ) ? $new_instance['target'] : '_self';
            $instance['link'] = strip_tags( $new_instance['link'] );
 
            if( empty( $instance['avia_key'] ) )
            {
                $key = $this->create_avia_key( $instance, $this->id );
                $instance['avia_key'] = $key;
                $this->cache['instances'][ $key ] = array();
                $this->update_cache();
            }
 
            $this->update_single_instance( $instance, $this->id );
 
            if( $this->activate_cron )
            {
                $this->restart_cron_job();
            }
 
            return $instance;
        }
 
        /**
         * Get info from instagram
         * based on https://gist.github.com/cosmocatalano/4544576
         *
         * SECURITY: sslverify is no longer disabled - the original code disabled TLS certificate
         * verification, which allowed a man-in-the-middle attacker to forge the "instagram" response
         * (and, downstream, control which files get downloaded and cached on the server).
         *
         * @since 4.3.1-secure hardened
         * @param string $username
         * @return array|\WP_Error
         */
        protected function scrape_instagram( $username )
        {
            $username = strtolower( $username );
            $username = str_replace( '@', '', $username );
 
            $remote = wp_remote_get( 'https://www.instagram.com/' . trim( $username ), array(
                    'timeout' => 60,
                    // SECURITY: sslverify intentionally left at the WP default (true).
                    // Do NOT set 'sslverify' => false here.
                ) );
 
            if ( is_wp_error( $remote ) )
            {
                return new WP_Error( 'site_down', __( 'Unable to communicate with Instagram.', 'avia_framework' ) );
            }
 
            $code = wp_remote_retrieve_response_code( $remote );
            if ( 200 != $code )
            {
                $msg = wp_remote_retrieve_response_message( $remote );
                if( empty( $msg ) )
                {
                    $msg = __( 'Unknown error code', 'avia_framework' );
                }
                return new WP_Error( 'invalid_response', sprintf( __( 'Instagram returned error %d (= %s).', 'avia_framework' ), $code, $msg ) );
            }
 
            $shards = explode( 'window._sharedData = ', $remote['body'] );
            if( ! isset( $shards[1] ) )
            {
                return new WP_Error( 'bad_json', __( 'Instagram has returned invalid data.', 'avia_framework' ) );
            }
 
            $insta_json = explode( ';</script>', $shards[1] );
            $insta_array = json_decode( $insta_json[0], true );
 
            if ( ! $insta_array )
            {
                return new WP_Error( 'bad_json', __( 'Instagram has returned invalid data.', 'avia_framework' ) );
            }
 
            if ( isset( $insta_array['entry_data']['ProfilePage'][0]['graphql']['user']['edge_owner_to_timeline_media']['edges'] ) )
            {
                $images = $insta_array['entry_data']['ProfilePage'][0]['graphql']['user']['edge_owner_to_timeline_media']['edges'];
            }
            else
            {
                return new WP_Error( 'bad_json_2', __( 'Instagram has returned invalid data.', 'avia_framework' ) );
            }
 
            if ( ! is_array( $images ) )
            {
                return new WP_Error( 'bad_array', __( 'Instagram has returned invalid data.', 'avia_framework' ) );
            }
 
            $instagram = array();
 
            foreach ( $images as $image )
            {
                if ( ! empty( $image['node']['is_video'] ) )
                {
                    $type = 'video';
                }
                else
                {
                    $type = 'image';
                }
 
                $caption = __( 'Instagram Image', 'avia_framework' );
 
                if ( ! empty( $image['node']['edge_media_to_caption']['edges'][0]['node']['text'] ) )
                {
                    $caption = wp_kses( $image['node']['edge_media_to_caption']['edges'][0]['node']['text'], array() );
                }
 
                // SECURITY: every URL taken from the remote response is passed through
                // is_allowed_download_url() before it is ever used - see download_from_instagram().
                $instagram[] = array(
                        'description'   => $caption,
                        'link'          => trailingslashit( '//instagram.com/p/' . $image['node']['shortcode'] ),
                        'time'          => $image['node']['taken_at_timestamp'] ?? 0,
                        'comments'      => $image['node']['edge_media_to_comment']['count'] ?? 0,
                        'likes'         => $image['node']['edge_liked_by']['count'] ?? 0,
                        'thumbnail'     => preg_replace( '/^https?\:/i', '', $image['node']['thumbnail_resources'][0]['src'] ?? '' ),
                        'small'         => preg_replace( '/^https?\:/i', '', $image['node']['thumbnail_resources'][2]['src'] ?? '' ),
                        'large'         => preg_replace( '/^https?\:/i', '', $image['node']['thumbnail_resources'][4]['src'] ?? '' ),
                        'original'      => preg_replace( '/^https?\:/i', '', $image['node']['display_url'] ?? '' ),
                        'type'          => $type,
                        'id'            => $image['node']['id']
                    );
            }
 
            $aviw_images_only = false;
            $aviw_images_only = apply_filters_deprecated( 'aviw_images_only', array( $aviw_images_only ), '4.3.1', 'avf_instagram_filter_files', __( 'Filter extended to filter images or videos', 'avia_framework' ) );
 
            $show = $aviw_images_only ? array( 'image' ) : array();
            $show = apply_filters( 'avf_instagram_filter_files', $show, $username );
 
            if( ! empty( $show ) )
            {
                foreach( $instagram as $key => $media_item )
                {
                    if( ! in_array( $media_item['type'], $show ) )
                    {
                        unset( $instagram[ $key ] );
                    }
                }
 
                $instagram = array_merge( $instagram );
            }
 
            if ( empty( $instagram ) )
            {
                return new WP_Error( 'no_images', __( 'Instagram did not return any images.', 'avia_framework' ) );
            }
 
            return $instagram;
        }
 
        /**
         * WP Cron handler for background uploads
         *
         * @since 4.3.1
         */
        public function handler_scheduled_filecheck()
        {
            if( defined( 'WP_DEBUG ' ) && WP_DEBUG )
            {
                error_log( '******************  In avia_instagram_widget::handler_scheduled_filecheck started' );
            }
 
            $this->schedule_cron_job( $this->expire_time * 2 );
 
            $settings = $this->get_settings();
            if( ! empty( $settings ) )
            {
                $this->check_all_instances();
            }
 
            $this->schedule_cron_job( $this->expire_time * 2 );
 
            $this->sync_data();
 
            $this->schedule_cron_job( $this->expire_time );
 
            if( defined( 'WP_DEBUG ' ) && WP_DEBUG )
            {
                error_log( '******************  In avia_instagram_widget::handler_scheduled_filecheck ended' );
            }
        }
 
        /**
         * Synchronises directory and cache data structure.
         *
         * @since 4.3.1
         */
        public function sync_data()
        {
            $settings = $this->get_settings();
 
            if( empty( $settings ) && empty( $this->cache['instances'] ) )
            {
                if( is_dir( $this->upload_folders['instagram_dir'] ) )
                {
                    avia_backend_delete_folder( $this->upload_folders['instagram_dir'] );
                    $this->cache['last_updated'] = time();
                    $this->update_cache();
                }
                return;
            }
 
            $instance_infos = (array) $this->cache['instances'];
 
            $keys = array_keys( $instance_infos );
            $keys_to_keep = array();
 
            foreach ( $settings as $index => $setting )
            {
                if( in_array( $setting['avia_key'], $keys ) )
                {
                    $keys_to_keep[] = $setting['avia_key'];
                }
            }
 
            $keys_to_remove = array_diff( $keys, $keys_to_keep );
 
            foreach( $keys_to_remove as $key )
            {
                $folder = $this->upload_folders['instagram_dir'] . $instance_infos[ $key ]['upload_folder'];
                avia_backend_delete_folder( $folder );
                unset( $this->cache['instances'][ $key ] );
            }
 
            $cache_dirs = is_dir( $this->upload_folders['instagram_dir'] ) ? scandir( $this->upload_folders['instagram_dir'] ) : false;
            if( ! is_array( $cache_dirs ) )
            {
                return;
            }
 
            $cache_dirs = array_diff( $cache_dirs, array( '.', '..' ) );
 
            $ref_dirs = array();
            foreach( $this->cache['instances'] as $key => $instance_info )
            {
                if( isset( $instance_info['upload_folder'] ) )
                {
                    $ref_dirs[] = $instance_info['upload_folder'];
                }
            }
 
            $remove_dirs = array_diff( $cache_dirs, $ref_dirs );
 
            foreach( $remove_dirs as $remove_dir )
            {
                avia_backend_delete_folder( $this->upload_folders['instagram_dir'] . $remove_dir );
            }
 
            if( empty( $this->cache['instances'] ) )
            {
                avia_backend_delete_folder( $this->upload_folders['instagram_dir'] );
            }
 
            $this->cache['last_updated'] = time();
            $this->update_cache();
        }
 
        /**
         * WP Cron is disabled - we have to load files during pageload in admin area
         *
         * @since 4.3.1
         */
        public function handler_init_filecheck()
        {
            $settings = $this->get_settings();
            if( empty( $settings ) )
            {
                if( $this->activate_cron  )
                {
                    $this->restart_cron_job();
                }
                return;
            }
 
            $instance = array_shift( $settings );
            if( ! isset( $instance['avia_key'] ) || empty( $instance['avia_key'] ) )
            {
                $instances = $this->get_settings();
                foreach( $instances as $key => &$instance )
                {
                    $instance = $this->parse_args_instance( $instance );
                    $key = $this->create_avia_key( $instance, $this->id_base . "-{$key}" );
                    $instance['avia_key'] = $key;
                    $this->cache['instances'][ $key ] = array();
                }
                unset( $instance );
                $this->save_settings( $instances );
 
                $this->cache['last_updated'] = 0;
                $this->update_cache();
 
                $this->check_all_instances();
            }
 
            if( $this->activate_cron  )
            {
                $this->restart_cron_job();
                return;
            }
 
            if( $this->cache['last_updated'] + $this->expire_time > time() )
            {
                return;
            }
 
            if( is_admin() )
            {
                $this->check_all_instances();
            }
        }
 
        /**
         * Is called, when an instance of a widget is deleted.
         *
         * @since 4.3.1
         * @param string $widget_id
         * @param string $sidebar_id
         * @param string $id_base
         */
        public function handler_delete_widget( $widget_id, $sidebar_id, $id_base )
        {
            $id = str_replace( $id_base . '-', '', $widget_id );
 
            $settings = $this->get_settings();
            if( empty( $settings ) || empty( $settings[ $id ] ) )
            {
                return;
            }
 
            $instance = $settings[ $id ];
 
            $instance_info = isset( $this->cache['instances'][ $instance['avia_key'] ] ) ? $this->cache['instances'][ $instance['avia_key'] ] : array();
            if( empty( $instance_info ) )
            {
                return;
            }
 
            $instance = $this->parse_args_instance( $instance );
            $instance_info = $this->parse_args_instance_cache( $instance_info );
 
            if( count( $settings ) <= 1 )
            {
                avia_backend_delete_folder( $this->upload_folders['instagram_dir'] );
                $this->cache['instances'] = array();
            }
            else
            {
                $folder = $this->upload_folders['instagram_dir'] . $instance_info['upload_folder'];
                avia_backend_delete_folder( $folder );
                unset( $this->cache['instances'][ $instance['avia_key'] ] );
            }
 
            $this->update_cache();
        }
 
        /**
         * @since 4.3.1
         */
        protected function restart_cron_job()
        {
           $timestamp = wp_next_scheduled( 'av_instagram_scheduled_filecheck' );
           if( false === $timestamp )
           {
               $this->schedule_cron_job( $this->expire_time );
               return;
           }
 
           if( $timestamp > ( time() + $this->expire_time * 2 ) )
           {
               $this->schedule_cron_job( $this->expire_time * 2 );
           }
        }
 
        /**
         * @since 4.3.1
         * @param int $delay_seconds
         * @return boolean
         */
        protected function schedule_cron_job( $delay_seconds = 0 )
        {
            $timestamp = wp_next_scheduled( 'av_instagram_scheduled_filecheck' );
            if( false !== $timestamp )
            {
                wp_unschedule_hook( 'av_instagram_scheduled_filecheck' );
            }
 
            $timestamp = time() + $delay_seconds;
 
            $scheduled = wp_schedule_single_event( $timestamp, 'av_instagram_scheduled_filecheck' );
 
            return false !== $scheduled;
        }
 
        /**
         * @since 4.3.1
         */
        protected function check_all_instances()
        {
            $settings = $this->get_settings();
 
            foreach ( $settings as $key => $instance )
            {
                $id_widget = $this->id_base . "-{$key}";
 
                if( false === is_active_widget( false, $id_widget, $this->id_base, false ) )
                {
                    continue;
                }
 
                $this->update_single_instance( $instance, $id_widget );
            }
 
            $this->cache['last_updated'] = time();
            $this->update_cache();
        }
 
        /**
         * @since 4.3.1
         * @param array $instance
         * @param string $id_widget
         * @return array
         */
        protected function update_single_instance( array $instance, $id_widget )
        {
            set_time_limit( 0 );
 
            $instance = $this->parse_args_instance( $instance );
 
            if( empty( $instance['avia_key'] ) )
            {
                $key = $this->create_avia_key( $instance, $id_widget );
                $instance['avia_key'] = $key;
                $this->cache['instances'][ $key ] = array();
            }
 
            $instance_cache = isset( $this->cache['instances'][ $instance['avia_key'] ] ) ? $this->cache['instances'][ $instance['avia_key'] ] : array();
            $instance_cache = $this->parse_args_instance_cache( $instance_cache );
 
            if( ( 'server' == $instance['cache'] ) && empty( $instance_cache['upload_folder'] ) && ! empty( $instance['username'] ) )
            {
                $id = str_replace( $this->id_base . '-', '', $id_widget );
                $f = empty( $instance['title'] ) ? $instance['username'] : $instance['title'];
                $folder_name = substr( AviaHelper::save_string( $id . '-' . $f, '-' ), 0, 30 );
                $folder = $this->upload_folders['instagram_dir'] . $folder_name;
 
                $created = avia_backend_create_folder( $folder, false, 'unique' );
                if( $created )
                {
                    $split = pathinfo( $folder );
                    $instance_cache['upload_folder'] = $split['filename'];
                    $instance_cache['path_error'] = '';
                    $instance_cache['cached_list'] = array();
                }
                else
                {
                    $instance_cache['path_error'] = sprintf( __( 'Unable to create cache folder "%s". Files will be loaded directly from instagram', 'avia_framework' ), $folder );
                }
            }
 
            $username = $instance['username'];
            $number = $instance['number'];
 
            if( ! empty( $username) )
            {
                $media_array = $this->scrape_instagram( $username );
 
                if ( ! is_wp_error( $media_array ) )
                {
                    $instance_cache['instagram_error'] = '';
                    $instance_cache['instagram_list'] = array_slice( $media_array, 0, $number );
 
                    if( 'server' == $instance['cache'] )
                    {
                        $instance_cache = $this->cache_files_in_upload_directory( $media_array, $instance, $instance_cache );
                    }
                }
                else
                {
                    $instance_cache['instagram_error'] = $media_array->get_error_message();
                }
            }
            else
            {
                $instance_cache['instagram_error'] = __( 'You need to specify an Instagram username.', 'avia_framework' );
                $instance_cache['instagram_list'] = array();
                $instance_cache['cached_list'] = array();
            }
 
            $instance_cache['last_update'] = time();
 
            $this->cache['instances'][ $instance['avia_key'] ] = $instance_cache;
            $this->update_cache();
 
            return $instance;
        }
 
        /**
         * Updates the local stored files in upload directory.
         *
         * @since 4.3.1
         * @param array $instagram_files
         * @param array $instance
         * @param array $instance_cache
         * @return array
         */
        protected function cache_files_in_upload_directory( array $instagram_files, array $instance, array $instance_cache )
        {
            set_time_limit( 0 );
 
            $cached_files = $instance_cache['cached_list'];
 
            $new_cached_files = array();
            $no_errors = 0;
 
            foreach( $instagram_files as $instagram_file )
            {
                $id = $instagram_file['id'];
 
                $found = false;
                foreach( $cached_files as $key_cache => $cached_file )
                {
                    if( $id == $cached_file['id'] )
                    {
                        if( ! empty( $cached_file['errors'] ) )
                        {
                            $this->remove_single_cached_files( $cached_file, $instance_cache );
                            unset( $cached_files[ $key_cache ] );
                            break;
                        }
 
                        $path = trailingslashit( $this->upload_folders['instagram_dir'] . $instance_cache['upload_folder'] );
                        foreach( $this->cached_file_sizes as $size )
                        {
                            if( empty( $cached_file[ $size ] ) || ! file_exists( $path . $cached_file[ $size ] ) )
                            {
                                $this->remove_single_cached_files( $cached_file, $instance_cache );
                                unset( $cached_files[ $key_cache ] );
                                break;
                            }
                        }
 
                        if( ! isset( $cached_files[ $key_cache ] ) )
                        {
                            break;
                        }
 
                        $ncf = $cached_file;
 
                        $ncf['description'] = $instagram_file['description'];
                        $ncf['link'] = $instagram_file['link'];
                        $ncf['time'] = $instagram_file['time'];
                        $ncf['comments'] = $instagram_file['comments'];
                        $ncf['likes'] = $instagram_file['likes'];
                        $ncf['type'] = $instagram_file['type'];
 
                        $new_cached_files[] = $ncf;
 
                        unset( $cached_files[ $key_cache ] );
                        $found = true;
                        break;
                    }
                }
 
                if( ! $found )
                {
                    $new_cached_files[] = $this->download_from_instagram( $instagram_file, $instance, $instance_cache );
                }
 
                $last = $new_cached_files[ count( $new_cached_files ) - 1 ];
 
                if( empty( $last['errors'] ) || ! empty( $last[ $instance['size'] ] ) )
                {
                    $no_errors++;
                }
 
                if( $no_errors >= $instance['number'] || count( $new_cached_files ) > ( $instance['number'] * 2 ) )
                {
                    break;
                }
            }
 
            if( $no_errors < $instance['number'] )
            {
                foreach( $cached_files as $key_cache => $cached_file )
                {
                    $new_cached_files[] = $cached_file;
                    if( empty( $cached_file['errors'] ) )
                    {
                        $no_errors++;
                    }
 
                    unset( $cached_files[ $key_cache ] );
 
                    if( $no_errors >= $instance['number'] )
                    {
                        break;
                    }
                }
            }
 
            foreach( $cached_files as $key_cache => $cached_file )
            {
                $this->remove_single_cached_files( $cached_file, $instance_cache );
                unset( $cached_files[ $key_cache ] );
            }
 
            $err_cnt = 0;
            $count = 1;
 
            foreach( $new_cached_files as $new_file )
            {
                if( ! empty( $new_file['errors'] ) )
                {
                    $err_cnt++;
                }
                $count++;
 
                if( $count > $instance['number'] )
                {
                    break;
                }
            }
 
            $instance_cache['upload_errors'] = ( 0 == $err_cnt ) ? false : $err_cnt;
            $instance_cache['cached_list'] = $new_cached_files;
 
            return $instance_cache;
        }
 
        /**
         * SECURITY: checks that a URL returned by instagram points to a host we explicitly
         * trust for media downloads, before we ever pass it to download_url(). Without this,
         * a compromised/forged response (e.g. via a MITM, or a future scraping bug) could make
         * this widget download and store an attacker-controlled file on the server.
         *
         * @since 4.3.1-secure
         * @param string $url
         * @return boolean
         */
        protected function is_allowed_download_url( $url )
        {
            $host = wp_parse_url( $url, PHP_URL_HOST );
 
            if( empty( $host ) )
            {
                return false;
            }
 
            $host = strtolower( $host );
 
            foreach( $this->allowed_download_hosts as $allowed )
            {
                $allowed = strtolower( $allowed );
 
                // exact match or proper subdomain match only (e.g. "scontent.cdninstagram.com" but not "evilcdninstagram.com")
                if( $host === $allowed || substr( $host, -( strlen( $allowed ) + 1 ) ) === '.' . $allowed )
                {
                    return true;
                }
            }
 
            return false;
        }
 
        /**
         * SECURITY: validates that a locally saved temp file is actually an image of an
         * allowed type and within the size limit. Rejects anything else (e.g. a script or
         * executable disguised behind an image-looking URL/filename).
         *
         * @since 4.3.1-secure
         * @param string $tmp_path
         * @return boolean
         */
        protected function is_valid_downloaded_image( $tmp_path )
        {
            if( ! file_exists( $tmp_path ) )
            {
                return false;
            }
 
            $filesize = filesize( $tmp_path );
            if( false === $filesize || $filesize <= 0 || $filesize > $this->max_file_size )
            {
                return false;
            }
 
            // getimagesize() actually parses the image header - a renamed .php file will fail this check.
            $info = @getimagesize( $tmp_path );
            if( false === $info || empty( $info['mime'] ) )
            {
                return false;
            }
 
            if( ! in_array( $info['mime'], $this->allowed_mime_types, true ) )
            {
                return false;
            }
 
            return true;
        }
 
        /**
         * Downloads the files from instagram and stores them in local cache.
         *
         * SECURITY (vs. original):
         * - source URL is checked against an allowlist of trusted CDN hosts before download
         * - downloaded file is verified to actually be an allowed image type/size before being kept
         * - filename is sanitized instead of trusting the remote-supplied name verbatim
         * - permissions reduced from 0777 to 0644
         *
         * @since 4.3.1
         * @since 4.3.1-secure hardened
         * @param array $instagram_file
         * @param array $instance
         * @param array $instance_cache
         * @return array
         */
        protected function download_from_instagram( array $instagram_file, array $instance, array $instance_cache )
        {
            $new_cached_file = $instagram_file;
            $new_cached_file['errors'] = array();
            $instagram_schema = 'https:';
 
            $cache_path = trailingslashit( $this->upload_folders['instagram_dir'] . $instance_cache['upload_folder'] );
 
            if( ! function_exists( 'download_url' ) )
            {
                require_once trailingslashit( ABSPATH ) . 'wp-admin/includes/file.php';
            }
 
            foreach( $this->cached_file_sizes as $size )
            {
                if( empty( $instagram_file[ $size ] ) )
                {
                    $new_cached_file[ $size ] = '';
                    continue;
                }
 
                $remote_url = $instagram_schema . $instagram_file[ $size ];
 
                // SECURITY: reject anything that doesn't point at a trusted instagram/meta CDN host.
                if( ! $this->is_allowed_download_url( $remote_url ) )
                {
                    $new_cached_file[ $size ] = '';
                    $new_cached_file['errors'][] = __( 'Rejected image URL from an untrusted host.', 'avia_framework' );
                    continue;
                }
 
                // SECURITY: sanitize the filename instead of trusting the remote name verbatim.
                $fn = explode( '?', basename( $instagram_file[ $size ] ) );
                $safe_name = sanitize_file_name( $fn[0] );
 
                if( empty( $safe_name ) )
                {
                    $new_cached_file[ $size ] = '';
                    $new_cached_file['errors'][] = __( 'Could not determine a safe filename for downloaded image.', 'avia_framework' );
                    continue;
                }
 
                $tmp_name = download_url( $remote_url, 30 );
 
                if( is_wp_error( $tmp_name ) )
                {
                    $new_cached_file[ $size ] = '';
                    $new_cached_file['errors'] = array_merge( $new_cached_file['errors'], $tmp_name->get_error_messages() );
                    continue;
                }
 
                // SECURITY: verify the downloaded file is actually an allowed image type/size
                // before it is moved into the public uploads folder.
                if( ! $this->is_valid_downloaded_image( $tmp_name ) )
                {
                    @unlink( $tmp_name );
                    $new_cached_file[ $size ] = '';
                    $new_cached_file['errors'][] = __( 'Downloaded file failed image validation and was discarded.', 'avia_framework' );
                    continue;
                }
 
                $new_file_name = $size . '_' . $safe_name;
                $new_name = $cache_path . $new_file_name;
 
                $moved = avia_backend_rename_file( $tmp_name, $new_name );
                if( is_wp_error( $moved ) )
                {
                    @unlink( $tmp_name );
                    $new_cached_file[ $size ] = '';
                    $new_cached_file['errors'] = array_merge( $new_cached_file['errors'], $moved->get_error_messages() );
                    continue;
                }
 
                // SECURITY: 0644 instead of 0777 - files only ever need to be world-readable, never world-writable/executable.
                if( ! chmod( $new_name, 0644 ) )
                {
                    $new_cached_file['errors'][] = sprintf( __( 'Could not change user rights of file %s to 644 - file might not be visible in frontend.', 'avia_framework' ), $new_name );
                }
 
                $new_cached_file[ $size ] = $new_file_name;
            }
 
            return $new_cached_file;
        }
 
        /**
         * Removes all cached files from $cached_file_info
         *
         * @since 4.3.1
         * @param array $cached_file_info
         * @param array $instance_cache
         * @return array
         */
        protected function remove_single_cached_files( array $cached_file_info, array $instance_cache )
        {
            $cache_path = trailingslashit( $this->upload_folders['instagram_dir'] . $instance_cache['upload_folder'] );
 
            foreach( $this->cached_file_sizes as $size )
            {
                if( ! empty( $cached_file_info[ $size ] ) )
                {
                    $file = $cache_path . $cached_file_info[ $size ];
 
                    if( file_exists( $file ) )
                    {
                        unlink( $file );
                    }
                    $cached_file_info[ $size ] = '';
                }
            }
 
            return $cached_file_info;
        }
    }
}

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎