/** * * @param array $current_import * @return bool */ function import(array $current_import) { // fetch the remote content $html = wp_remote_get($current_import['file']); // Something failed if (is_wp_error($html)) { $redirect_url = get_admin_url(get_current_blog_id(), '/tools.php?page=pb_import'); error_log('\\PressBooks\\Import\\Html import error, wp_remote_get() ' . $html->get_error_message()); $_SESSION['pb_errors'][] = $html->get_error_message(); $this->revokeCurrentImport(); \Pressbooks\Redirect\location($redirect_url); } $url = parse_url($current_import['file']); // get parent directory (with forward slash e.g. /parent) $path = dirname($url['path']); $domain = $url['scheme'] . '://' . $url['host'] . $path; // get id (there will be only one) $id = array_keys($current_import['chapters']); // front-matter, chapter, or back-matter $post_type = $this->determinePostType($id[0]); $chapter_parent = $this->getChapterParent(); $body = $this->kneadandInsert($html['body'], $post_type, $chapter_parent, $domain); // Done return $this->revokeCurrentImport(); }
/** * Runs activation function and sets up default WP options for new blog, * a.k.a. when a registered user creates a new blog * * @param int $blog_id * @param int $user_id * * @see add_action( 'wpmu_new_blog', ... ) */ function wpmuNewBlog($blog_id, $user_id) { $this->blog_id = (int) $blog_id; $this->user_id = (int) $user_id; switch_to_blog($this->blog_id); if (!$this->isBookSetup()) { $this->wpmuActivate(); array_walk($this->opts, function ($v, $k) { if (empty($v)) { delete_option($k); } else { update_option($k, $v); } }); wp_cache_flush(); } // Set current metadata version to skip redundant upgrade routines update_option('pressbooks_metadata_version', \Pressbooks\Metadata::$currentVersion); flush_rewrite_rules(false); do_action('pressbooks_new_blog'); restore_current_blog(); if (is_user_logged_in()) { (new \Pressbooks\Catalog())->deleteCache(); \Pressbooks\Redirect\location(get_admin_url($this->blog_id)); } }
/** * Imports user selected chapters from an instance of PB * * @param array $chapters * Array( [5] => Array( [222] => chapter ) [14] => Array( [164] => front-matter ) ) * @return type */ function import(array $chapters) { $this->chapters = $chapters; $chapters_to_import = $this->getChapters(); libxml_use_internal_errors(true); foreach ($chapters_to_import as $new_post) { // Load HTMl snippet into DOMDocument using UTF-8 hack $utf8_hack = '<?xml version="1.0" encoding="UTF-8"?>'; $doc = new \DOMDocument(); $doc->loadHTML($utf8_hack . $new_post['post_content']); // Download images, change image paths $doc = $this->scrapeAndKneadImages($doc); $html = $doc->saveXML($doc->documentElement); // Remove auto-created <html> <body> and <!DOCTYPE> tags. $html = preg_replace('/^<!DOCTYPE.+?>/', '', str_replace(array('<html>', '</html>', '<body>', '</body>'), array('', '', '', ''), $html)); $import_post = array('post_title' => $new_post['post_title'], 'post_content' => $html, 'post_type' => $new_post['post_type'], 'post_status' => $new_post['post_status']); // set post parent if ('chapter' == $new_post['post_type']) { $post_parent = $this->getChapterParent(); $import_post['post_parent'] = $post_parent; } // woot, woot! $pid = wp_insert_post($import_post); // check for errors, redirect and record if (is_wp_error($pid)) { error_log('\\PBT\\Import\\PBImport()->import error at `wp_insert_post()`: ' . $pid->get_error_message()); \PBT\Search\ApiSearch::revokeCurrentImport(); \Pressbooks\Redirect\location(get_bloginfo('url') . '/wp-admin/admin.php?page=api_search_import'); } // set post metadata $this->setPostMeta($pid, $new_post); \Pressbooks\Book::consolidatePost($pid, get_post($pid)); } return \PBT\Search\ApiSearch::revokeCurrentImport(); }
/** * Force the user to edit custom-css posts in our custom editor. */ function redirect_css_editor() { $post_id = absint(@$_REQUEST['post']); if (!$post_id) { return; // Do nothing } $post = get_post($post_id); if (!$post) { return; // Do nothing } if ('custom-css' != $post->post_type) { return; // Do nothing } $redirect_url = get_admin_url(get_current_blog_id(), '/themes.php?page=pb_custom_css&slug=' . $post->post_name); \Pressbooks\Redirect\location($redirect_url); }
/** * Catch form submissions * * @see pressbooks/templates/admin/import.php */ public static function formSubmit() { // -------------------------------------------------------------------------------------------------------- // Sanity check if (false == static::isFormSubmission() || false == current_user_can('edit_posts')) { // Don't do anything in this function, bail. return; } // -------------------------------------------------------------------------------------------------------- // Determine at what stage of the import we are and do something about it $redirect_url = get_admin_url(get_current_blog_id(), '/tools.php?page=pb_import'); $current_import = get_option('pressbooks_current_import'); // Revoke if (@$_GET['revoke'] && check_admin_referer('pb-revoke-import')) { self::revokeCurrentImport(); \Pressbooks\Redirect\location($redirect_url); } // only html import uses a url, not a file path if (0 !== strcmp($current_import['type_of'], 'html')) { // Appends 'last part' of the path to the dynamic first part of the path ($upload_dir) $upload_dir = wp_upload_dir(); $current_import['file'] = trailingslashit($upload_dir['path']) . basename($current_import['file']); } if (@$_GET['import'] && is_array(@$_POST['chapters']) && is_array($current_import) && isset($current_import['file']) && check_admin_referer('pb-import')) { // -------------------------------------------------------------------------------------------------------- // Do Import @set_time_limit(300); $ok = false; switch ($current_import['type_of']) { case 'epub': $importer = new Epub\Epub201(); $ok = $importer->import($current_import); break; case 'wxr': $importer = new Wordpress\Wxr(); $ok = $importer->import($current_import); break; case 'odt': $importer = new Odf\Odt(); $ok = $importer->import($current_import); break; case 'docx': $importer = new Ooxml\Docx(); $ok = $importer->import($current_import); break; case 'html': $importer = new Html\Xhtml(); $ok = $importer->import($current_import); } $msg = "Tried to import a file of type {$current_import['type_of']} and "; $msg .= $ok ? 'succeeded :)' : 'failed :('; self::log($msg, $current_import); if ($ok) { // Success! Redirect to organize page $success_url = get_admin_url(get_current_blog_id(), '/admin.php?page=pressbooks'); \Pressbooks\Redirect\location($success_url); } } elseif (@$_GET['import'] && !@empty($_FILES['import_file']['name']) && @$_POST['type_of'] && check_admin_referer('pb-import')) { // -------------------------------------------------------------------------------------------------------- // Set the 'pressbooks_current_import' option $allowed_file_types = array('epub' => 'application/epub+zip', 'xml' => 'application/xml', 'odt' => 'application/vnd.oasis.opendocument.text', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'); $overrides = array('test_form' => false, 'mimes' => $allowed_file_types); if (!function_exists('wp_handle_upload')) { require_once ABSPATH . 'wp-admin/includes/file.php'; } $upload = wp_handle_upload($_FILES['import_file'], $overrides); if (!empty($upload['error'])) { // Error, redirect back to form $_SESSION['pb_notices'][] = $upload['error']; \Pressbooks\Redirect\location($redirect_url); } $ok = false; switch ($_POST['type_of']) { case 'wxr': $importer = new Wordpress\Wxr(); $ok = $importer->setCurrentImportOption($upload); break; case 'epub': $importer = new Epub\Epub201(); $ok = $importer->setCurrentImportOption($upload); break; case 'odt': $importer = new Odf\Odt(); $ok = $importer->setCurrentImportOption($upload); break; case 'docx': $importer = new Ooxml\Docx(); $ok = $importer->setCurrentImportOption($upload); break; } $msg = "Tried to upload a file of type {$_POST['type_of']} and "; $msg .= $ok ? 'succeeded :)' : 'failed :('; self::log($msg, $upload); if (!$ok) { // Not ok? $_SESSION['pb_errors'][] = sprintf(__('Your file does not appear to be a valid %s.', 'pressbooks'), strtoupper($_POST['type_of'])); unlink($upload['file']); } } elseif (@$_GET['import'] && 'html' === @$_POST['type_of'] && check_admin_referer('pb-import')) { // check if it's a valid url if (false == filter_var($_POST['import_html'], FILTER_VALIDATE_URL)) { $_SESSION['pb_errors'][] = __('Your URL does not appear to be valid', 'pressbooks'); \Pressbooks\Redirect\location($redirect_url); } // HEAD request, check for a valid response from server $remote_head = wp_remote_head($_POST['import_html']); // Something failed if (is_wp_error($remote_head)) { error_log('\\Pressbooks\\Modules\\Import::formSubmit html import error, wp_remote_head()' . $remote_head->get_error_message()); $_SESSION['pb_errors'][] = $remote_head->get_error_message(); \Pressbooks\Redirect\location($redirect_url); } // weebly.com (and likely some others) prevent HEAD requests, but allow GET requests if (200 !== $remote_head['response']['code'] && 405 !== $remote_head['response']['code']) { $_SESSION['pb_errors'][] = __('The website you are attempting to reach is not returning a successful response header on a HEAD request: ', 'pressbooks') . $remote_head['response']['code']; \Pressbooks\Redirect\location($redirect_url); } // ensure the media type is HTML (not JSON, or something we can't deal with) if (false === strpos($remote_head['headers']['content-type'], 'text/html') && false === strpos($remote_head['headers']['content-type'], 'application/xhtml+xml')) { $_SESSION['pb_errors'][] = __('The website you are attempting to reach is not returning HTML content', 'pressbooks'); \Pressbooks\Redirect\location($redirect_url); } // GET http request $body = wp_remote_get($_POST['import_html']); // check for wp error if (is_wp_error($body)) { $error_message = $body->get_error_message(); error_log('\\Pressbooks\\Modules\\Import::formSubmit error, import_html' . $error_message); $_SESSION['pb_errors'][] = $error_message; \Pressbooks\Redirect\location($redirect_url); } // check for a successful response code on GET request if (200 !== $body['response']['code']) { $_SESSION['pb_errors'][] = __('The website you are attempting to reach is not returning a successful response on a GET request: ', 'pressbooks') . $body['response']['code']; \Pressbooks\Redirect\location($redirect_url); } // add our url $body['url'] = $_POST['import_html']; $importer = new Html\Xhtml(); $ok = $importer->setCurrentImportOption($body); $msg = "Tried to upload a file of type {$_POST['type_of']} and "; $msg .= $ok ? 'succeeded :)' : 'failed :('; self::log($msg, $body['headers']); if (!$ok) { // Not ok? $_SESSION['pb_errors'][] = sprintf(__('Your file does not appear to be a valid %s.', 'pressbooks'), strtoupper($_POST['type_of'])); } } // Default, back to form \Pressbooks\Redirect\location($redirect_url); }
/** * Uses v1/api to get an array of public books from a PB instance * * @param string $endpoint API url * @return array of books * [2] => Array( * [title] => Brad can has book * [author] => Brad Payne * [license] => cc-by-sa * ) * [5] => Array( * [title] => Help, I'm a Book! * [author] => Frank Zappa * [license] => cc-by-nc-sa * ) */ static function getPublicBooks($endpoint, $search = '') { $books = array(); $current_book = get_current_blog_id(); $domain = parse_url($endpoint, PHP_URL_HOST); $titles = !empty($search) ? '?titles=' . $search : ''; // build the url, get list of public books $public_books = wp_remote_get($endpoint . 'books' . '/' . $titles); if (is_wp_error($public_books)) { error_log('\\PBT\\Search\\getPublicBooks error: ' . $public_books->get_error_message()); \Pressbooks\Redirect\location(get_bloginfo('url') . '/wp-admin/admin.php?page=api_search_import'); } $public_books_array = json_decode($public_books['body'], true); // something goes wrong at the API level/response if (0 == $public_books_array['success']) { return; } // a valid response if (false !== $public_books_array) { foreach ($public_books_array['data'] as $id => $val) { $books[$id] = array('title' => $public_books_array['data'][$id]['book_meta']['pb_title'], 'author' => $public_books_array['data'][$id]['book_meta']['pb_author'], 'license' => $public_books_array['data'][$id]['book_meta']['pb_book_license'], 'domain' => $domain); if (0 === strcmp('all-rights-reserved', $books[$id]['license'])) { unset($books[$id]); } } } // don't return results from the book where the search is happening, only if searching this instance of PB if (isset($books[$current_book]) && $endpoint == network_home_url()) { unset($books[$current_book]); } if (!empty($books)) { // cache public books for 12 hours set_transient('pbt-public-books-' . $domain, $books, 43200); } return $books; }
/** * Add Book by URL */ static function formAddByUrl() { check_admin_referer('bulk-books'); // Nonce auto-generated by WP_List_Table $catalog = new static(); $user_id = $catalog->getUserId(); // Set Redirect URL if (get_current_user_id() != $user_id) { $redirect_url = get_admin_url(get_current_blog_id(), '/index.php?page=pb_catalog&user_id=' . $user_id); } else { $redirect_url = get_admin_url(get_current_blog_id(), '/index.php?page=pb_catalog'); } $url = parse_url(\Pressbooks\Sanitize\canonicalize_url($_REQUEST['add_book_by_url'])); $main = parse_url(network_site_url()); if (strpos($url['host'], $main['host']) === false) { $_SESSION['pb_errors'][] = __('Invalid URL.', 'pressbooks'); \Pressbooks\Redirect\location($redirect_url); } if ($url['host'] == $main['host']) { // Get slug using the path $slug = str_replace($main['path'], '', $url['path']); $slug = trim($slug, '/'); $slug = explode('/', $slug); $slug = $slug[0]; } else { // Get slug using host $slug = str_replace($main['host'], '', $url['host']); $slug = trim($slug, '.'); $slug = explode('.', $slug); $slug = $slug[0]; } $book_id = get_id_from_blogname($slug); if (!$book_id) { $_SESSION['pb_errors'][] = __('No book found.', 'pressbooks'); \Pressbooks\Redirect\location($redirect_url); } // if ( ! get_blog_option( $book_id, 'blog_public' ) ) { // $_SESSION['pb_errors'][] = __( 'Book is not public', 'pressbooks' ); // \Pressbooks\Redirect\location( $redirect_url ); // } $catalog->saveBook($book_id, array()); $catalog->deleteCache(); // Ok! $_SESSION['pb_notices'][] = __('Settings saved.'); // Redirect back to form \Pressbooks\Redirect\location($redirect_url); }
/** * Redirect away from (what we consider) bad WordPress admin pages */ function redirect_away_from_bad_urls() { if (is_super_admin()) { return; // Do nothing } $check_against_url = parse_url((is_ssl() ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], PHP_URL_PATH); $redirect_url = get_site_url(get_current_blog_id(), '/wp-admin/'); // --------------------------------------------------------------------------------------------------------------- // If user is on post-new.php, check for valid post_type if (preg_match('~/wp-admin/post-new\\.php$~', $check_against_url)) { if (!in_array(@$_REQUEST['post_type'], \Pressbooks\PostType\list_post_types())) { $_SESSION['pb_notices'][] = __('Unsupported post type.', 'pressbooks'); \Pressbooks\Redirect\location($redirect_url); } } // --------------------------------------------------------------------------------------------------------------- // Don't let user go to any of these pages, under any circumstance $restricted = array('edit-tags', 'export', 'import', 'link-(manager|add)', 'nav-menus', 'options-(discussion|media|permalink|reading|writing)', 'plugin-(install|editor)', 'theme-editor', 'update-core', 'widgets'); // Todo: Fine grained control over: options-general.php $expr = '~/wp-admin/(' . implode('|', $restricted) . ')\\.php$~'; if (preg_match($expr, $check_against_url)) { $_SESSION['pb_notices'][] = __('You do not have sufficient permissions to access that URL.', 'pressbooks'); \Pressbooks\Redirect\location($redirect_url); } }
/** * Save custom CSS to database (and filesystem) * * @see pressbooks/templates/admin/custom-css.php */ static function formSubmit() { if (false == static::isFormSubmission() || false == current_user_can('edit_theme_options')) { // Don't do anything in this function, bail. return; } // Process form if ('yes' == @$_GET['customcss'] && isset($_POST['my_custom_css']) && check_admin_referer('pb-custom-css')) { $slug = isset($_POST['slug']) ? $_POST['slug'] : 'web'; $redirect_url = get_admin_url(get_current_blog_id(), '/themes.php?page=pb_custom_css&slug=' . $slug); if (md5(NONCE_KEY . @$_POST['post_id']) != @$_POST['post_id_integrity']) { // A hacker trying to overwrite posts?. error_log('\\Pressbooks\\CustomCss::formSubmit error: unexpected value for post_id_integrity'); \Pressbooks\Redirect\location($redirect_url . '&customcss_error=true'); } // Write to database $my_post = array('ID' => absint($_POST['post_id']), 'post_content' => static::cleanupCss($_POST['my_custom_css'])); $response = wp_update_post($my_post, true); if (is_wp_error($response)) { // Something went wrong? error_log('\\Pressbooks\\CustomCss::formSubmit error, wp_update_post(): ' . $response->get_error_message()); \Pressbooks\Redirect\location($redirect_url . '&customcss_error=true'); } // Write to file $my_post['post_content'] = stripslashes($my_post['post_content']); // We purposely send \\A0 to WordPress, but we want to send \A0 to the file system $filename = static::getCustomCssFolder() . sanitize_file_name($slug . '.css'); file_put_contents($filename, $my_post['post_content']); // Update "version" update_option('pressbooks_last_custom_css', time()); // Ok! \Pressbooks\Redirect\location($redirect_url); } }
/** * Catch form submissions * * @see pressbooks/templates/admin/export.php */ static function formSubmit() { if (false == static::isFormSubmission() || false == current_user_can('edit_posts')) { // Don't do anything in this function, bail. return; } // Set locale to UTF8 so escapeshellcmd() doesn't strip valid characters. setlocale(LC_CTYPE, 'UTF8', 'en_US.UTF-8'); putenv('LC_CTYPE=en_US.UTF-8'); // Override some WP behaviours when exporting \Pressbooks\Sanitize\fix_audio_shortcode(); // Download if (!empty($_GET['download_export_file'])) { $filename = sanitize_file_name($_GET['download_export_file']); static::downloadExportFile($filename); } // Delete if (isset($_POST['delete_export_file']) && isset($_POST['filename']) && check_admin_referer('pb-delete-export')) { $filename = sanitize_file_name($_POST['filename']); $path = static::getExportFolder(); unlink($path . $filename); delete_transient('dirsize_cache'); /** @see get_dirsize() */ \Pressbooks\Redirect\location(get_admin_url(get_current_blog_id(), '/admin.php?page=pb_export')); } // Export if ('yes' == @$_GET['export'] && is_array(@$_POST['export_formats']) && check_admin_referer('pb-export')) { // -------------------------------------------------------------------------------------------------------- // Define modules $x = $_POST['export_formats']; $modules = array(); if (isset($x['pdf'])) { $modules[] = '\\Pressbooks\\Modules\\Export\\Prince\\Pdf'; } if (isset($x['print_pdf'])) { $modules[] = '\\Pressbooks\\Modules\\Export\\Prince\\PrintPdf'; } if (isset($x['mpdf'])) { $modules[] = '\\Pressbooks\\Modules\\Export\\Mpdf\\Pdf'; } if (isset($x['epub'])) { $modules[] = '\\Pressbooks\\Modules\\Export\\Epub\\Epub201'; // Must be set before MOBI } if (isset($x['epub3'])) { $modules[] = '\\Pressbooks\\Modules\\Export\\Epub\\Epub3'; // Must be set before MOBI } if (isset($x['mobi'])) { if (!isset($x['epub'])) { // Make sure Epub source file is generated $modules[] = '\\Pressbooks\\Modules\\Export\\Epub\\Epub201'; // Must be set before MOBI } $modules[] = '\\Pressbooks\\Modules\\Export\\Mobi\\Kindlegen'; // Must be set after EPUB } if (isset($x['icml'])) { $modules[] = '\\Pressbooks\\Modules\\Export\\InDesign\\Icml'; } if (isset($x['xhtml'])) { $modules[] = '\\Pressbooks\\Modules\\Export\\Xhtml\\Xhtml11'; } if (isset($x['wxr'])) { $modules[] = '\\Pressbooks\\Modules\\Export\\WordPress\\Wxr'; } if (isset($x['vanillawxr'])) { $modules[] = '\\Pressbooks\\Modules\\Export\\WordPress\\VanillaWxr'; } if (isset($x['odt'])) { $modules[] = '\\Pressbooks\\Modules\\Export\\Odt\\Odt'; } // -------------------------------------------------------------------------------------------------------- // Clear cache? Range is 1 hour. $last_export = get_option('pressbooks_last_export'); $within_range = time() - $last_export; if ($within_range > 60 * 60) { \Pressbooks\Book::deleteBookObjectCache(); update_option('pressbooks_last_export', time()); } // -------------------------------------------------------------------------------------------------------- // Do Export @set_time_limit(300); $redirect_url = get_admin_url(get_current_blog_id(), '/admin.php?page=pb_export'); $conversion_error = array(); $validation_warning = array(); $outputs = array(); foreach ($modules as $module) { /** @var \Pressbooks\Modules\Export\Export $exporter */ $exporter = new $module(array()); if (!$exporter->convert()) { $conversion_error[$module] = $exporter->getOutputPath(); } else { if (!$exporter->validate()) { $validation_warning[$module] = $exporter->getOutputPath(); } } // Add to outputs array $outputs[$module] = $exporter->getOutputPath(); // Stats hook do_action('pressbooks_track_export', substr(strrchr($module, '\\'), 1)); } delete_transient('dirsize_cache'); /** @see get_dirsize() */ // -------------------------------------------------------------------------------------------------------- // MOBI cleanup if (isset($x['mobi']) && !isset($x['epub'])) { unlink($outputs['\\Pressbooks\\Modules\\Export\\Epub\\Epub201']); } // -------------------------------------------------------------------------------------------------------- // No errors? if (empty($conversion_error) && empty($validation_warning)) { // Ok! \Pressbooks\Redirect\location($redirect_url); } // -------------------------------------------------------------------------------------------------------- // Error exceptions if (isset($validation_warning['\\Pressbooks\\Modules\\Export\\Prince\\Pdf'])) { // The PDF is garbage and we don't want the user to have it. // Delete file. Report error instead of warning. unlink($validation_warning['\\Pressbooks\\Modules\\Export\\Prince\\Pdf']); $conversion_error['\\Pressbooks\\Modules\\Export\\Prince\\Pdf'] = $validation_warning['\\Pressbooks\\Modules\\Export\\Prince\\Pdf']; unset($validation_warning['\\Pressbooks\\Modules\\Export\\Prince\\Pdf']); } if (isset($validation_warning['\\Pressbooks\\Modules\\Export\\Prince\\PrintPdf'])) { // The PDF is garbage and we don't want the user to have it. // Delete file. Report error instead of warning. unlink($validation_warning['\\Pressbooks\\Modules\\Export\\Prince\\PrintPdf']); $conversion_error['\\Pressbooks\\Modules\\Export\\Prince\\PrintPdf'] = $validation_warning['\\Pressbooks\\Modules\\Export\\Prince\\PrintPdf']; unset($validation_warning['\\Pressbooks\\Modules\\Export\\Prince\\PrintPdf']); } // -------------------------------------------------------------------------------------------------------- // Errors :( if (count($conversion_error)) { // Conversion error \Pressbooks\Redirect\location($redirect_url . '&export_error=true'); } if (count($validation_warning)) { // Validation warning \Pressbooks\Redirect\location($redirect_url . '&export_warning=true'); } } }
/** * */ function restrict_access() { global $wpdb; $user = wp_get_current_user(); $restricted = $wpdb->get_results("SELECT * FROM {$wpdb->sitemeta} WHERE meta_key = 'pressbooks_network_managers'"); if ($restricted) { $restricted = maybe_unserialize($restricted[0]->meta_value); } else { $restricted = array(); } $check_against_url = parse_url((is_ssl() ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], PHP_URL_PATH); $redirect_url = get_site_url() . '/wp-admin/network/'; // --------------------------------------------------------------------------------------------------------------- // Don't let user go to any of these pages, under any circumstances $restricted_urls = array('themes', 'theme-(install|editor)', 'plugins', 'plugin-(install|editor)', 'settings', 'update-core', 'upgrade'); $expr = '~/wp-admin/network/(' . implode('|', $restricted_urls) . ')\\.php$~'; if (in_array($user->ID, $restricted) && preg_match($expr, $check_against_url)) { \Pressbooks\Redirect\location($redirect_url); } }