/**
 * Render function for Media Vault custom column in WP Media Library list table.
 *
 * @since 0.4
 *
 * @uses mgjp_mv_get_the_permissions()
 * @param $column_name string name-id of current column
 * @param $post_id int ID of post being evaluated
 */
function mgjp_mv_render_media_library_custom_column($column_name, $post_id)
{
    if ('mgjp_mv_info' != $column_name) {
        return;
    }
    if (!($permission = mgjp_mv_get_the_permission($post_id))) {
        return;
    }
    $permissions = mgjp_mv_get_the_permissions();
    $permission = isset($permissions[$permission]) ? $permissions[$permission] : '';
    $description = isset($permission['description']) && !empty($permission['description']) ? esc_html($permission['description']) : '<span class="mgjp-mv-error">' . esc_html__('Undetermined! Permissions have been misconfigured for this attachment!', 'media-vault') . '</span>';
    ?>

    <em><?php 
    esc_html_e('Protected Media', 'media-vault');
    ?>
</em>

    <p>

      <div><?php 
    esc_html_e('Files accessible to:', 'media-vault');
    ?>
</div>

      <em><?php 
    echo $description;
    ?>
</em>

    </p>

  <?php 
}
/**
 * Check if the current user is permitted to access an attachment of a
 * specified ID
 *
 * @since 0.7
 *
 * @uses mgjp_mv_get_the_permission()
 * @uses mgjp_mv_get_the_permissions()
 * @param $attachment_id int The id of the attachment to check against
 * @return bool True if current user access permitted
 * @return bool False if current user access denied
 */
function mgjp_mv_check_user_permitted($attachment_id)
{
    // check if attachment has protection and permissions set on it
    if (!($permission = mgjp_mv_get_the_permission($attachment_id))) {
        return true;
    }
    $permissions = mgjp_mv_get_the_permissions();
    // check if permission set on attachment is valid
    if (!isset($permissions[$permission])) {
        return false;
    }
    // it is better to fail safely than to reveal something we should not
    // check if permission check is set to need not run in admin
    if (is_admin() && isset($permissions[$permission]['run_in_admin']) && !$permissions[$permission]['run_in_admin']) {
        return true;
    }
    // check if permission check is set to need the user to be logged in. if it is check if he is logged in
    if (!isset($permissions[$permission]['logged_in']) || $permissions[$permission]['logged_in'] && !is_user_logged_in()) {
        return false;
    }
    // check if permission callback is set to false
    if (isset($permissions[$permission]['cb']) && false === $permissions[$permission]['cb']) {
        return true;
    }
    // if not false (above), check if permission callback is valid, fail safely if it is not
    if (!is_callable($permissions[$permission]['cb'])) {
        return false;
    }
    // perform the defined permission check callback on the user for this attachment
    // function MUST return true if the user is allowed access
    $permission_check = call_user_func($permissions[$permission]['cb'], $attachment_id);
    // if there are no errors permit access
    if (true === $permission_check) {
        return true;
    }
    return false;
}
/**
 * Check if file with path $rel_file from WP uploads folder is in a Media Vault protected folder.
 * If it is, verify the user requesting it has permission to access it. After they pass the check,
 * If the 'safeforce' flag has been set for $action, send HTTP Headers forcing file download,
 * otherwise send normal headers and serve the file.
 *
 * @since 0.1
 *
 * @uses mgjp_mv_upload_dir()
 * @uses mgjp_mv_get_the_permissions()
 * @param string $rel_file Filesystem path or filename, must be relative to the WP uploads folder
 * @param string $action Force Download Flag, only acceptable value is 'safeforce'
 */
function mgjp_mv_get_file($rel_file, $action = '')
{
    // $rel_file = path to the file to view/download,
    // relative to the WP uploads folder
    // (eg:'/media-vault/2013/10/media-vault-150x150.jpg')
    $upload_dir = wp_upload_dir();
    // only files in the WP uploads directory are allowed to be accessed:
    $file = rtrim($upload_dir['basedir'], '/') . str_replace('..', '', isset($rel_file) ? $rel_file : '');
    //---Basic Checks----------------------------------------------------//
    if (!$upload_dir['basedir'] || !is_file($file)) {
        status_header(404);
        wp_die('404. File not found.');
    }
    $mime = wp_check_filetype($file);
    // Check filetype against allowed filetypes
    if (isset($mime['type']) && $mime['type']) {
        $mimetype = $mime['type'];
    } else {
        status_header(403);
        wp_die(__('403. Forbidden.<br/>You cannot directly access files of this type in this directory on this server. Please contact the website administrator.'));
    }
    //---Permission Checks-----------------------------------------------//
    $file_info = pathinfo($rel_file);
    // check if file is protected by checking
    // if it is in the protected folder before
    // doing any permission checks
    if (0 === stripos($file_info['dirname'] . '/', mgjp_mv_upload_dir('/', true))) {
        // disable caching of this page by caching plugins ------//
        if (!defined('DONOTCACHEPAGE')) {
            define('DONOTCACHEPAGE', 1);
        }
        if (!defined('DONOTCACHEOBJECT')) {
            define('DONOTCACHEOBJECT', 1);
        }
        if (!defined('DONOTMINIFY')) {
            define('DONOTMINIFY', 1);
        }
        //-------------------------------------------------------//
        // try and get attachment id from url -------------------//
        global $wpdb;
        $attachments = $wpdb->get_results($wpdb->prepare("\n        SELECT      post_id, meta_value\n        FROM        {$wpdb->postmeta}\n        WHERE       meta_key = %s\n                    AND meta_value LIKE %s\n        ", '_wp_attachment_metadata', '%' . $file_info['basename'] . '%'), ARRAY_A);
        $attachment_id = false;
        foreach ($attachments as $attachment) {
            $meta_value = unserialize($attachment['meta_value']);
            if (ltrim(dirname($meta_value['file']), '/') == ltrim($file_info['dirname'], '/')) {
                $attachment_id = $attachment['post_id'];
                break;
            }
        }
        // ------------------------------------------------------//
        if (!($permission = mgjp_mv_get_the_permission($attachment_id))) {
            $permission = get_option('mgjp_mv_default_permission', 'logged-in');
        }
        $permissions = mgjp_mv_get_the_permissions();
        // permission set up error detection
        $standard_error_txt = ' ' . esc_html__('Therefore for safety and privacy reasons this file is unavailable. Please contact the website administrator.', 'media-vault') . '<p><a href="' . home_url() . '">&larr;' . esc_html__('Return to homepage', 'media-vault') . '</a></p>';
        if (!isset($permissions[$permission])) {
            wp_die(__('The permissions set for this file are not recognized.', 'media-vault') . $standard_error_txt);
        }
        if (!isset($permissions[$permission]['logged_in'])) {
            $errors[] = 'logged_in';
        }
        if (!isset($permissions[$permission]['cb'])) {
            $errors[] = 'cb';
        }
        if (isset($errors)) {
            $error_txt = __('The permissions set for this file have left the following important parameters undefined:', 'media-vault') . '<ul><li>\'' . implode('\'</li><li>\'', $errors) . '\'</li></ul>' . '<p>' . $standard_error_txt . '</p>';
            wp_die($error_txt);
        }
        if ($permissions[$permission]['logged_in']) {
            is_user_logged_in() || auth_redirect();
        }
        // using is_user_logged_in is lighter than using just auth_redirect
        if (false !== $permissions[$permission]['cb']) {
            if (!is_callable($permissions[$permission]['cb'])) {
                wp_die(__('The permission checking function set in this file\'s permissions is not callable.', 'media-vault') . $standard_error_txt);
            }
            $permission_check = call_user_func_array($permissions[$permission]['cb'], array($attachment_id, $rel_file, $file));
            if (is_wp_error($permission_check)) {
                wp_die($permission_check->get_error_message() . $standard_error_txt);
            }
            if (true !== $permission_check) {
                wp_die(__('You do not have sufficient permissions to view this file.', 'media-vault') . $standard_error_txt);
            }
        }
    }
    // end of permission checks
    //-------------------------------------------------------------------//
    header('Content-Type: ' . $mimetype);
    // always send this
    if (false === strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS')) {
        header('Content-Length: ' . filesize($file));
    }
    if ('safeforce' !== $action) {
        //--OPEN FILE IN BROWSER functions-------------//
        $last_modified = gmdate('D, d M Y H:i:s', filemtime($file));
        $etag = '"' . md5($last_modified) . '"';
        header("Last-Modified: {$last_modified} GMT");
        header('ETag: ' . $etag);
        header('Cache-Control: no-store, no-cache, must-revalidate');
        // HTTP 1.1.
        header('Pragma: no-cache');
        // HTTP 1.0.
        header('Expires: Thu, 01 Dec 1994 16:00:00 GMT');
        // Proxies
        // Support for Conditional GET
        $client_etag = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : false;
        if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
            $_SERVER['HTTP_IF_MODIFIED_SINCE'] = false;
        }
        $client_last_modified = trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
        // If string is empty, return 0. If not, attempt to parse into a timestamp
        $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
        // Make a timestamp for our most recent modification...
        $modified_timestamp = strtotime($last_modified);
        if ($client_last_modified && $client_etag ? $client_modified_timestamp >= $modified_timestamp && $client_etag == $etag : $client_modified_timestamp >= $modified_timestamp || $client_etag == $etag) {
            status_header(304);
            exit;
        }
    } else {
        //--FORCE DOWNLOAD Functions-----------------------//
        // required for IE, otherwise Content-disposition is ignored
        if (ini_get('zlib.output_compression')) {
            ini_set('zlib.output_compression', 'Off');
        }
        header('Pragma: public');
        // required
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Cache-Control: private', false);
        // required for certain browsers
        header('Content-Disposition: attachment; filename="' . $file_info['basename'] . '";');
        header('Content-Transfer-Encoding: binary');
    }
    // If we made it this far, just serve the file
    if (ob_get_length()) {
        ob_clean();
    }
    flush();
    readfile($file);
    exit;
}
/**
 * Render the default file access permission field
 *
 * @since 0.4
 *
 * @param array Array of arguments passed the specific settings field
 */
function mgjp_mv_render_default_permission_field($args)
{
    $default_permission = get_option('mgjp_mv_default_permission', 'logged-in');
    ?>

  <select id="mgjp_mv_default_permission" name="mgjp_mv_default_permission">

    <?php 
    foreach (mgjp_mv_get_the_permissions() as $permission => $data) {
        ?>

      <option value="<?php 
        echo esc_attr($permission);
        ?>
" <?php 
        selected($default_permission, $permission);
        ?>
>
        <?php 
        echo esc_html($data['select']);
        ?>
      </option>

    <?php 
    }
    ?>

  </select>
  <span class="description">
    <?php 
    esc_html_e('Select the default permissions required for accessing protected media uploads.', 'media-vault');
    ?>
  </span>

  <?php 
}
/**
 * Save Media Vault attachment metabox data on
 * edit attachments
 *
 * @since 0.7.1
 *
 * @uses mgjp_mv_move_attachment_from_protected()
 * @uses mgjp_mv_move_attachment_to_protected()
 * @uses mgjp_mv_get_the_permissions()
 * @param $attachment_id the id of the current attachment
 * @return void if any of the validations fail
 */
function mgjp_mv_save_attachment_metabox_data($attachment_id)
{
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return;
    }
    if (!isset($_POST['mgjp_mv_protection_metabox_nonce']) || !wp_verify_nonce($_POST['mgjp_mv_protection_metabox_nonce'], 'mgjp_mv_protection_metabox')) {
        return;
    }
    if (!current_user_can('edit_post', $attachment_id)) {
        return;
    }
    if (!isset($_POST['mgjp_mv_protection_toggle'])) {
        return;
    }
    switch ($_POST['mgjp_mv_protection_toggle']) {
        case 'off':
            remove_action('edit_attachment', 'mgjp_mv_save_attachment_metabox_data');
            $move = mgjp_mv_move_attachment_from_protected($attachment_id);
            add_action('edit_attachment', 'mgjp_mv_save_attachment_metabox_data');
            if (is_wp_error($move)) {
                return;
            }
            delete_post_meta($attachment_id, '_mgjp_mv_permission');
            return;
        case 'on':
            remove_action('edit_attachment', 'mgjp_mv_save_attachment_metabox_data');
            $move = mgjp_mv_move_attachment_to_protected($attachment_id);
            add_action('edit_attachment', 'mgjp_mv_save_attachment_metabox_data');
            if (is_wp_error($move)) {
                return;
            }
            if (!isset($_POST['mgjp_mv_permission_select']) || empty($_POST['mgjp_mv_permission_select'])) {
                return;
            }
            $permissions = mgjp_mv_get_the_permissions();
            if ('default' == $_POST['mgjp_mv_permission_select'] || !isset($permissions[$_POST['mgjp_mv_permission_select']])) {
                delete_post_meta($attachment_id, '_mgjp_mv_permission');
            } else {
                update_post_meta($attachment_id, '_mgjp_mv_permission', $_POST['mgjp_mv_permission_select']);
            }
            return;
        default:
            return;
    }
}