<?php
/* Prohibit direct script loading */
defined('ABSPATH') || die('No direct script access allowed!');
use Joomunited\WPMediaFolder\WpmfHelper;
use Joomunited\Queue\JuMainQueue;

/**
 * Class JUQueueHelper
 */
class JUQueueHelper
{

    /**
     * All WPMF terms
     * Variable used as a cache to not retrieved terms each time the
     * method is called
     *
     * @var null
     */
    protected static $terms = null;

    /**
     * Update folder name and move files
     *
     * @param integer $folder_id   Folder id
     * @param string  $folder_name Folder name
     *
     * @return void
     */
    public static function updateFolderName($folder_id, $folder_name)
    {
        // Get children folders
        $folders = self::getChildTerms($folder_id);

        $folders[] = (int)$folder_id;

        foreach ($folders as $folder) {
            // Get attachments in this folder
            $attachments = get_posts(array(
                'post_type' => 'attachment',
                'numberposts' => -1,
                'tax_query' => array(
                    array(
                        'taxonomy' => WPMF_TAXO,
                        'field' => 'id',
                        'terms' => $folder,
                        'include_children' => false
                    )
                ),
                'meta_query' => array(
                    'relation' => 'AND',
                    array(
                        'key'     => 'wpmf_drive_id',
                        'compare' => 'NOT EXISTS'
                    ),
                    array(
                        'key'     => 'wpmf_awsS3_info',
                        'compare' => 'NOT EXISTS'
                    )
                )
            ));

            $folders_path = self::getParentTerms($folder);
            $folders_path_string = implode(DIRECTORY_SEPARATOR, $folders_path);
            $wpmfQueue = JuMainQueue::getInstance('wpmf');
            foreach ($attachments as $attachment) {
                $datas = array(
                    'post_id' => $attachment->ID,
                    'destination' => $folders_path_string,
                    'with_filename' => false,
                    'delete_folder' => true,
                    'update_database' => true,
                    'action' => 'wpmf_physical_folders'
                );
                $wpmfQueue->addToQueue($datas);
            }
            $wpmfQueue->proceedQueueAsync();
        }
    }

    /**
     * Get recursively all child terms of a given term
     *
     * @param integer $parent Term we want to find the children of
     *
     * @return array
     */
    protected static function getChildTerms($parent)
    {
        // get all direct decendents of the $parent
        $terms = get_terms(array(
            'taxonomy' => WPMF_TAXO,
            'parent' => $parent,
            'hide_empty' => false
        ));
        $children = array();

        // go through all the direct decendents of $parent
        foreach ($terms as $term) {
            // recurse to get the direct decendents of the current term
            $children = array_merge($children, self::getChildTerms($term->term_id));

            $children[] = $term->term_id;
        }

        return $children;
    }

    /**
     * Retrieve all WPMF terms
     *
     * @return array
     */
    public static function getAllTerms()
    {
        // Retrieve all folders
        $wpterms = get_terms(
            array(
                'taxonomy' => WPMF_TAXO,
                'hide_empty' => false
            )
        );

        // Associate folders by term id
        $terms = array();
        foreach ($wpterms as $term) {
            $terms[$term->term_id] = $term;
        }

        return $terms;
    }

    /**
     * Retrieve all parent terms
     *
     * @param integer $term Term we want to find parents of
     *
     * @return array
     */
    public static function getParentTerms($term)
    {
        if ($term === 0) {
            return array();
        }

        // Retrieve all WPMF terms
        self::$terms = self::getAllTerms();
        // Initialize array that will contain all parent folders
        $folders = array();
        $current_folder = $term;
        // Retrieve parents one by one
        do {
            $current_term = self::$terms[$current_folder];
            $folders[] = $current_term->name;
            $current_folder = $current_term->parent;
        } while ($current_term->parent);

        return array_reverse($folders);
    }

    /**
     * Move a file and its thumbnails physically
     *
     * @param array   $datas               Data details
     * @param boolean $is_wpml_translation Is this file a wpml translation of another moved file?
     *
     * @return boolean|WP_Error true on success or WP_ERROR
     */
    public static function moveFile($datas = array(), $is_wpml_translation = false)
    {
        WP_Filesystem();
        global $wp_filesystem;
        global $wpdb;

        // Sanitize destination path
        foreach ($datas as $param => $data) {
            ${$param} = $data;
        }
        $destination = self::sanitizePath($destination);
        if ($with_filename && !strlen(trim($destination, '/'))) {
            JuMainQueue::log('Error : destination file empty');
            return true;
        }

        $related_files = array('original' => array(), 'thumbnails' => array(), 'backups' => array());

        $wp_uploads = wp_upload_dir();

        // Retrieve attachment full path
        $related_files['original']['path'] = get_attached_file($post_id, 1);
        $related_files['original']['url'] = wp_get_attachment_url($post_id);
        if (!$related_files['original']['path'] || !$related_files['original']['url']) {
            JuMainQueue::log('Error : Attachment %s not found', $$post_id);
            return true;
        }

        // Remove file name from path and url
        $base_path = pathinfo($related_files['original']['path'], PATHINFO_DIRNAME);
        $url_parts = explode('/', $related_files['original']['url']);
        unset($url_parts[count($url_parts)-1]); // Remove the filename from parts
        $base_url = implode('/', $url_parts);

        // Check that the file is located inside the WordPress upload dir
        if (strpos($base_url, $wp_uploads['baseurl']) !== 0 || strpos($base_path, $wp_uploads['basedir']) !== 0) {
            JuMainQueue::log('Error : file is not int the upload folder %s', $base_path);
            return true;
        }

        // Make url and path relative to the wordpress installation
        $base_path = str_replace($wp_uploads['basedir'], '', $base_path);
        $base_url = str_replace($wp_uploads['baseurl'], '', $base_url);

        // Replace windows
        $base_path = str_replace(DIRECTORY_SEPARATOR, '/', $base_path);

        // Apply relative path to the original file and url
        $related_files['original']['path'] = str_replace($wp_uploads['basedir'], '', $related_files['original']['path']);
        $related_files['original']['url'] = str_replace($wp_uploads['baseurl'], '', $related_files['original']['url']);

        // Retrieve file extension from thumbnail name
        $extension = explode('.', $related_files['original']['path']);
        $extension = $extension[count($extension)-1];

        if ($with_filename) {
            $filename = $destination . '.' . $extension;
        } else {
            $filename = $destination . '/' . pathinfo($related_files['original']['path'], PATHINFO_BASENAME);
        }
        $related_files['original']['new_path'] = '/' . ltrim($filename, '/');
        $related_files['original']['new_url'] = '/' .  ltrim($filename, '/');

        // Retrieve all meta to extract the tumbnails
        $meta = wp_get_attachment_metadata($post_id);
        if (isset($meta['sizes']) && is_array($meta['sizes'])) {
            foreach ($meta['sizes'] as &$size) {
                // Add to array original url and path
                $file = array(
                    'path' => $base_path . '/' . $size['file'],
                    'url' => $base_url . '/' . $size['file']
                );

                // Retrieve file extension from thumbnail name
                $extension = explode('.', $size['file']);
                $extension = $extension[count($extension) - 1];

                if ($with_filename) {
                    $filename = $destination . '-' . (int)$size['width'] . 'x' . (int)$size['height'] . '.' . $extension;

                    // Update meta filename
                    $size['file'] = pathinfo($filename, PATHINFO_BASENAME);
                } else {
                    $filename = $destination . '/' . $size['file'];
                }
                $file['new_path'] = '/' . ltrim($filename, '/');
                $file['new_url'] = '/' . ltrim($filename, '/');

                $related_files['thumbnails'][] = $file;
            }
        }

        if (isset($meta['file'])) {
            $meta['file'] = ltrim($related_files['original']['new_path'], '/');
        }

        // Retrieve the backups of the images
        $backup_sizes = get_post_meta($post_id, '_wp_attachment_backup_sizes', true);
        if ($backup_sizes && is_array($backup_sizes)) {
            foreach ($backup_sizes as $backup_size) {
                $destination_folder = $destination;
                if ($with_filename) {
                    // Remove filename from destination var
                    $destination_folder = explode('/', $destination_folder);
                    unset($destination_folder[count($destination_folder)-1]);
                    $destination_folder = implode('/', $destination_folder);
                }

                $related_files['backups'][] = array(
                    'path' => $base_path . '/' . $backup_size['file'],
                    'url' => $base_url . '/' . $backup_size['file'],
                    'new_path' => '/' . $destination_folder . '/' . $backup_size['file'],
                    'new_url' => '/' . $destination_folder . '/' . $backup_size['file']
                );
            }
        }

        // get original image
        if (isset($meta['original_image'])) {
            // Add to array original url and path
            $file = array(
                'path' => $base_path . '/' . $meta['original_image'],
                'url' => $base_url . '/' . $meta['original_image']
            );

            // Retrieve file extension from thumbnail name
            $filename = $destination . '/' . $meta['original_image'];
            $file['new_path'] = '/' . ltrim($filename, '/');
            $file['new_url'] = '/' . ltrim($filename, '/');
            $file['width'] = $meta['width'];
            $file['height'] = $meta['height'];
            $file['filesize'] = $meta['filesize'];
            $related_files['backups'][] = $file;
        }

        $original_file = $wp_uploads['basedir'] . $related_files['original']['path'];
        $new_file = $wp_uploads['basedir'] . $related_files['original']['new_path'];
        $override = (defined('WPMF_PHYSICAL_OVERRIDE')) ? true : false;
        // Check if source file exists
        if (file_exists($original_file) && is_file($original_file)) {
            if (realpath($original_file) !== realpath($new_file)) {
                // Check is there is already a destination file with this name
                if (!$override) {
                    if (file_exists($new_file)) {
                        JuMainQueue::log('Error : file is %s already exists', $new_file);
                        return true;
                    }
                } else {
                    if (file_exists($new_file)) {
                        $current_file_id = attachment_url_to_postid($wp_uploads['baseurl'] . $related_files['original']['new_path']);
                        if (!empty($current_file_id)) {
                            WpmfHelper::replace($current_file_id, $new_file, $original_file);
                            $folders = get_the_terms($current_file_id, WPMF_TAXO);
                            if (!empty($folders)) {
                                $folder = $folders[0]->term_id;
                                $parents = self::getParentTerms($folder);
                                $destination = implode(DIRECTORY_SEPARATOR, $parents);
                            }

                            $meta_data = wp_get_attachment_metadata($current_file_id);
                            $dirname = _wp_get_attachment_relative_path($meta_data['file']);
                            if ($dirname) {
                                $dirname = trailingslashit($dirname);
                            }

                            if ($dirname === '') {
                                $meta_data['file'] = $destination . '/' . $meta_data['file'];
                            } else {
                                $meta_data['file'] = str_replace($dirname, $destination . '/', $meta_data['file']);
                            }

                            wp_update_attachment_metadata($current_file_id, $meta_data);
                            if (!$datas['update_database'] && (int)$current_file_id !== (int)$post_id) {
                                $datas = array(
                                    'post_id' => $post_id,
                                    'action' => 'wpmf_delete_attachment'
                                );
                                $wpmfQueue = JuMainQueue::getInstance('wpmf');
                                $wpmfQueue->addToQueue($datas);
                            }
                        }
                        return true;
                    }
                }

                // Create directory
                $dir = pathinfo($new_file, PATHINFO_DIRNAME);
                if (!file_exists($dir)) {
                    wp_mkdir_p($dir);
                }

                // Move actual file
                if (!$wp_filesystem->move(
                    $original_file,
                    $new_file,
                    $override
                )) {
                    JuMainQueue::log('Error : moving file %s to %s went wrong', $original_file, $new_file);
                    return true;
                }
                JuMainQueue::log('Info : file moved from %s to %s', $original_file, $new_file);
            } elseif (!$is_wpml_translation) {
                JuMainQueue::log('Error : source and destination file are the same %s', $new_file);
                return true;
            }
        } elseif (!$is_wpml_translation) {
            JuMainQueue::log('Error : file %s does not exist', $original_file);
            return true;
        }
        // if file is a wpml translation, the file may have already been moved by the calling function
        // Update file meta (_wp_attached_file)
        if (ltrim($related_files['original']['path'], '/') !== ltrim($related_files['original']['new_path'], '/')) {
            if (update_post_meta($post_id, '_wp_attached_file', ltrim($related_files['original']['new_path'], '/')) !== true) {
                JuMainQueue::log('Error : updating post meta failed %s %s', $post_id, ltrim($related_files['original']['new_path'], '/'));
                return true;
            }
        }

        // Todo update guid via sql query ???
        // Array containing all actually moved files to be replaced in db
        $done_files = array();
        $done_files[] = $related_files['original'];

        // Move all thumbnails and backup files
        foreach (array($related_files['thumbnails'], $related_files['backups']) as $file_type) {
            foreach ($file_type as $file) {
                $original_file = $wp_uploads['basedir'] . $file['path'];
                $new_file = $wp_uploads['basedir'] . $file['new_path'];
                if (file_exists($original_file)) {
                    if (!$wp_filesystem->move($original_file, $new_file, $override)) {
                        JuMainQueue::log('Error : related file move failed from %s to %s', $original_file, $new_file);
                        continue;
                    }
                } elseif (!$is_wpml_translation) {
                    JuMainQueue::log('Error: related file doesn not exist %s', $original_file);
                    continue;
                }

                $done_files[] = $file;
                JuMainQueue::log('Info : related file moved from %s to %s', $original_file, $new_file);
            }
        }

        // Update thumbnails meta
        if (!empty($meta)) {
            wp_update_attachment_metadata($post_id, $meta);
        }

        // Update wpml translation attachments and thumbnails
        if (!$is_wpml_translation && function_exists('icl_object_id')) {
            $post_translations = array();

            $query = 'SELECT * FROM `' . $wpdb->prefix . 'icl_translations` WHERE trid=(SELECT trid FROM `' . $wpdb->prefix . 'icl_translations` WHERE element_type="post_attachment" AND element_id=' . (int)$post_id . ') AND element_id<>' . (int)$post_id;
            // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query escaped previously
            $post_translations = $wpdb->get_results($query, ARRAY_A);

            foreach ($post_translations as $translation) {
                $translation_post_meta = get_post_meta($translation['element_id'], '_wp_attached_file', true);

                if ($translation_post_meta === ltrim($related_files['original']['path'], '/')) {
                    // This is the same exact file

                    // Update _wp_attached_file key
                    if (update_post_meta($translation['element_id'], '_wp_attached_file', ltrim($related_files['original']['new_path'], '/')) !== true) {
                        JuMainQueue::log('Error : updating post meta failed %s %s', $translation['element_id'], ltrim($related_files['original']['new_path'], '/'));
                        continue;
                    }

                    $translation_meta = wp_get_attachment_metadata($translation['element_id']);
                    if (isset($translation_meta['file']) && $translation_meta['file'] === ltrim($related_files['original']['path'], '/')) {
                        $translation_meta['file'] = ltrim($related_files['original']['new_path'], '/');
                    }

                    // Only basename is saved in the _wp_attachment_metadata sizes col, no need to do anything if we only change the folder
                    if ($with_filename && isset($translation_meta['sizes']) && is_array($translation_meta['sizes'])) {
                        // Loop over the sizes of this translation attachment
                        foreach ($translation_meta['sizes'] as &$size) {
                            // Loop over the thumbnails already moved to see if this one of them
                            foreach ($related_files['thumbnails'] as $thumbnail) {
                                if (pathinfo($thumbnail['path'], PATHINFO_BASENAME) === $size['file'] &&
                                    pathinfo($translation_post_meta, PATHINFO_DIRNAME) === pathinfo(ltrim($thumbnail['path'], '/'), PATHINFO_DIRNAME)) { // Make this thumbnail is not a thumbnail in another folder
                                    // Update meta filename
                                    $size['file'] = pathinfo($thumbnail['new_path'], PATHINFO_BASENAME);
                                    continue;
                                }
                            }
                        }
                    }
                    preg_match('/(do_action|apply_filters)\(.*\);/', $match, $hook_matches);

                    if (!empty($translation_meta)) {
                        wp_update_attachment_metadata($translation['element_id'], $translation_meta);
                    }
                } else {
                    // This is not the same file but still it has to be in the same folder, lets move all of them (main file, thumbnails, backups)
                    $new_path = pathinfo($related_files['original']['new_path'], PATHINFO_DIRNAME);
                    self::moveFile(array(
                        'post_id' => $translation['element_id'],
                        'destination' => $new_path,
                        'with_filename' => false,
                        'delete_folder' => $delete_folder,
                        'update_database' => $update_database,
                        'action' => 'wpmf_physical_folders'
                    ), true);

                    if ($with_filename) {
                        // At this points backups have been moved but still it has to be renamed in the db
                        $backup_sizes = get_post_meta($translation['element_id'], '_wp_attachment_backup_sizes', true);

                        if (!empty($backup_sizes) &&
                            isset($backup_sizes['full-orig']) &&
                            $backup_sizes['full-orig']['file'] === ltrim($related_files['original']['path'], '/')) {
                            foreach ($backup_sizes as $backup_name => &$backup_size) {
                                if ($backup_name === 'full-orig') {
                                    $backup_size['file'] = ltrim($related_files['original']['new_path'], '/');
                                } else {
                                    // Retrieve file extension from thumbnail name
                                    $extension = explode('.', $backup_size['file']);
                                    $extension = $extension[count($extension) - 1];

                                    $backup_size['file'] = $destination . '-' . (int)$backup_size['width'] . 'x' . (int)$backup_size['height'] . '.' . $extension;
                                }
                            }

                            update_post_meta($translation['element_id'], '_wp_attachment_backup_sizes', $backup_sizes);
                        }
                    }
                }
            }
        }

        if ($delete_folder) {
            $dir = pathinfo($wp_uploads['basedir'] . '/' . $related_files['original']['path'], PATHINFO_DIRNAME);
            self::deleteDirectory($dir);
        }

        // Replace in database file url
        $options = get_option('wpmf_queue_options');

        if (!empty($options['auto_detect_tables'])) {
            $tables = self::getDefaultDbColumns();
        } else {
            $tables = wpmfGetOption('wp-media-folder-tables');
        }

        if (!$update_database) {
            JuMainQueue::log('Info : Database update not required');
            return true;
        }

        foreach ($done_files as $done_file) {
            foreach ($tables as $table => &$columns) {
                if (!count($columns)) {
                    continue;
                }

                // Get the primary key of the table
                $key = $wpdb->get_row('SHOW KEYS FROM  ' . esc_sql($table) . ' WHERE Key_name = "PRIMARY"');

                // No primary key, we can't do anything in this table
                if ($key === null) {
                    JuMainQueue::log('No primary key in table', $table);
                    continue;
                }

                $key = $key->Column_name;

                $count_records = $wpdb->get_var('SELECT COUNT(' . esc_sql($key) . ') FROM ' . esc_sql($table));
                $limit = 200;
                $total_pages = ceil($count_records/$limit);
                for ($i = 1; $i <= $total_pages; $i++) {
                    $datas = array(
                        'table' => $table,
                        'columns' => $columns,
                        'page' => (int)$i,
                        'limit' => (int)$limit,
                        'key' => $key,
                        'done_file' => $done_file,
                        'action' => 'wpmf_replace_physical_url'
                    );
                    $row = JuMainQueue::checkQueueExist(json_encode($datas));
                    if (!$row) {
                        JuMainQueue::addToQueue($datas);
                    }
                }
            }
        }

        return true;
    }

    /**
     * Replace physical URL in database
     *
     * @param boolean $result     Result
     * @param array   $datas      Data details
     * @param integer $element_id ID of queue element
     *
     * @return boolean
     */
    public static function replacePhysicalUrl($result, $datas, $element_id)
    {
        global $wpdb;
        $table = $datas['table'];
        $columns = $datas['columns'];
        $key = $datas['key'];
        $done_file = $datas['done_file'];
        $offset = ((int)$datas['page'] - 1)*(int)$datas['limit'];
        $wp_uploads = wp_upload_dir();
        foreach ($columns as $column => $column_value) {
            // Search for serialized strings
            $query = 'SELECT ' . esc_sql($key) . ',' . esc_sql($column) . ' FROM ' . esc_sql($table). ' WHERE
                        ' . esc_sql($column) . ' REGEXP \'s:[0-9]+:".*(' . esc_sql(preg_quote($wp_uploads['baseurl'] . $done_file['url'])) . '|' . esc_sql(preg_quote($done_file['url'])) . ').*";\' LIMIT '. esc_sql($datas['limit']) .' OFFSET ' . esc_sql($offset);

            // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query escaped previously
            $results = $wpdb->get_results($query, ARRAY_N);

            if (count($results)) {
                foreach ($results as $result) {
                    $unserialized_var = unserialize($result[1]);
                    if ($unserialized_var !== false) {
                        // We're sure this is a serialized value, proceed it here
                        unset($columns[$column]);
                        // Actually replace string in all available strin array and properties
                        $unserialized_var = self::replaceStringRecursive($unserialized_var, $done_file['url'], $done_file['new_url']);
                        $unserialized_var = self::replaceStringRecursive($unserialized_var, $wp_uploads['baseurl'] . $done_file['url'], $wp_uploads['baseurl'] . $done_file['new_url']);
                        // Serialize it back
                        $serialized_var = serialize($unserialized_var);

                        // Update the database with new serialized value
                        $nb_rows = $wpdb->query($wpdb->prepare(
                            'UPDATE ' . esc_sql($table) . ' SET ' . esc_sql($column) . '=%s WHERE ' . esc_sql($key) . '=%s AND meta_key NOT IN("_wp_attached_file", "_wp_attachment_metadata")',
                            array($serialized_var, $result[0])
                        ));
                        JuMainQueue::log('Update serialized data (%s row affected) : %s', $nb_rows, $query);
                    }
                }
            }
        }

        if (count($columns)) {
            $columns_query = array();

            foreach ($columns as $column => $column_value) {
                if (!empty($options['replace_relative_paths'])) {
                    // Relative urls
                    $columns_query[] = '`' . $column . '` = replace(`' . esc_sql($column) . '`, "' . esc_sql($done_file['url']) . '", "' . esc_sql($done_file['new_url']) . '")';
                }
                $columns_query[] = '`' . $column . '` = replace(`' . esc_sql($column) . '`, "' . esc_sql($wp_uploads['baseurl'] .  $done_file['url']) . '", "' . esc_sql($wp_uploads['baseurl'] . $done_file['new_url']) . '")';
            }

            $query = 'UPDATE `' . esc_sql($table) . '` SET ' . implode(',', $columns_query);

            // Ignore attachments meta column
            if ($table === $wpdb->prefix . 'postmeta') {
                $query .= ' WHERE meta_key NOT IN("_wp_attached_file", "_wp_attachment_metadata")';
            }

            // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query escaped previously
            $nb_rows = $wpdb->query($query);
            JuMainQueue::log('Query (%s row affected) : %s', $nb_rows, $query);
        }
        return true;
    }

    /**
     * Recursively parse a variable to replace a string
     *
     * @param mixed  $var     Variable to replace string into
     * @param string $search  String to search
     * @param string $replace String to replace with
     *
     * @return mixed
     */
    private static function replaceStringRecursive($var, $search, $replace)
    {
        switch (gettype($var)) {
            case 'string':
                return str_replace($search, $replace, $var);

            case 'array':
                foreach ($var as &$property) {
                    $property = self::replaceStringRecursive($property, $search, $replace);
                }
                return $var;

            case 'object':
                foreach (get_object_vars($var) as $property_name => $property_value) {
                    $var->{$property_name} = self::replaceStringRecursive($property_value, $search, $replace);
                }
                return $var;
        }
    }

    /**
     * Sanitize a file path
     *
     * @param string $path Path
     *
     * @return string
     */
    private static function sanitizePath($path)
    {
        // Replace non unix space separators by /
        $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);

        $path = explode('/', $path);

        $stack = array();
        foreach ($path as $seg) {
            // Remove all dots segments
            if ($seg === '..' || $seg === '.') {
                // Ignore this segment
                continue;
            }

            // Remove all non matching characters
            $seg = sanitize_file_name($seg);

            if (strlen($seg)) {
                $stack[] = $seg;
            }
        }

        return implode('/', $stack);
    }

    /**
     * Return a list the main image and all thumbnails of the attachment
     *
     * @param integer $post_id Attachment id
     *
     * @return array
     */
    private static function getAllImagesUrl($post_id)
    {
        $images = array();

        // Add main image
        $images['original'] = wp_get_attachment_url($post_id);

        foreach (get_intermediate_image_sizes() as $size) {
            $image = image_downsize($post_id, $size);

            if ($image !== false && $image[3] === true) {
                $images[$image[1] . 'x' . $image[2]] = $image[0];
            }
        }
        return array_unique($images);
    }

    /**
     * Get all text assimilated columns from database
     *
     * @param boolean $all Retrive only prefix tables or not
     *
     * @return array|null|object
     */
    public static function getDbColumns($all)
    {
        global $wpdb;
        $extra_query = '';

        // Not forced to retrieve all tables
        if (!$all) {
            // If option not set to look for all tables
            $options = get_option('wpmf_queue_options');
            if (empty($options['search_full_database'])) {
                $extra_query = ' AND TABLE_NAME LIKE "'.$wpdb->prefix.'%" ';
            }
        }

        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Nothing to prepare
        return $wpdb->get_results('SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE DATA_TYPE IN ("varchar", "text", "tinytext", "mediumtext", "longtext") AND TABLE_SCHEMA = "'.DB_NAME.'" '.$extra_query.' ORDER BY TABLE_NAME', OBJECT);
    }


    /**
     * Get the columns that can contain images
     *
     * @return array
     */
    public static function getDefaultDbColumns()
    {
        $columns = self::getDbColumns(false);

        $final_columns = array();

        foreach ($columns as $column) {
            $matches = array();
            preg_match('/varchar\(([0-9]+)\)/', $column->COLUMN_TYPE, $matches);

            if (count($matches) && (int)$matches[1] < 40) {
                continue;
            }

            if (!isset($final_columns[$column->TABLE_NAME])) {
                $final_columns[$column->TABLE_NAME] = array();
            }
            $final_columns[$column->TABLE_NAME][$column->COLUMN_NAME] = 1;
        }

        return $final_columns;
    }

    /**
     * Generate a random string
     *
     * @param integer $length Length of the returned string
     *
     * @author https://stackoverflow.com/questions/4356289/php-random-string-generator#answer-4356295
     *
     * @return string
     */
    public static function getRandomString($length = 20)
    {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $charactersLength = strlen($characters);
        $randomString = '';
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[rand(0, $charactersLength - 1)];
        }
        return $randomString;
    }

    /**
     * Delete a folder
     *
     * @param WP_Term $folder_term Detail of folder
     *
     * @return void
     */
    public static function deleteFolder($folder_term)
    {
        // Sanitize folder path
        $folders_path = array();
        if ($folder_term->parent !== 0) {
            $folders_path = self::getParentTerms($folder_term->parent);
        }
        $folders_path[] = $folder_term->name;
        $folders_path_string = implode(DIRECTORY_SEPARATOR, $folders_path);

        $wp_uploads = wp_upload_dir();
        $directory = $wp_uploads['basedir'] . DIRECTORY_SEPARATOR . self::sanitizePath($folders_path_string);
        self::deleteDirectory($directory);
    }

    /**
     * Delete an actual directory if it's empty
     *
     * @param string $directory Directory
     *
     * @return void
     */
    public static function deleteDirectory($directory)
    {
        if (!file_exists($directory)) {
            JuMainQueue::log('Info : Directory doesn\'t exist ' . $directory);
            return;
        }
        $dir_files = glob($directory . DIRECTORY_SEPARATOR . '*');
        if (!empty($dir_files)) {
            JuMainQueue::log('Info : Directory not empty ' . $directory);
        } else {
            JuMainQueue::log('Info : Removing empty directory ' . $directory);
            rmdir($directory);
        }
    }
}
