Filesystem.php000064400000020174150212456520007407 0ustar00_document_root = $this->set_document_root( ABSPATH ); } /** * Gets the document root for this application * * @param string $type Must be one of plugins, plugins_mu, templates, styles, content, gallery, or root * @return string */ public function get_document_root( $type = 'root' ) { switch ( $type ) { case 'plugins': case 'plugin': $retval = WP_PLUGIN_DIR; break; case 'plugins_mu': case 'plugin_mu': $retval = WPMU_PLUGIN_DIR; break; case 'templates': case 'template': case 'themes': case 'theme': $retval = \get_template_directory(); break; case 'styles': case 'style': case 'stylesheets': case 'stylesheet': $retval = \get_stylesheet_directory(); break; case 'content': $retval = WP_CONTENT_DIR; break; case 'gallery': case 'galleries': $root_type = NGG_GALLERY_ROOT_TYPE; if ( 'content' == $root_type ) { $retval = WP_CONTENT_DIR; } else { $retval = $this->_document_root; } break; default: $retval = $this->_document_root; } return \wp_normalize_path( $retval ); } public function get_absolute_path( $path ) { $parts = \array_filter( \explode( DIRECTORY_SEPARATOR, $path ), 'strlen' ); $absolutes = []; foreach ( $parts as $part ) { if ( '.' == $part ) { continue; } if ( '..' == $part ) { \array_pop( $absolutes ); } else { $absolutes[] = $part; } } return \wp_normalize_path( \implode( DIRECTORY_SEPARATOR, $absolutes ) ); } /** * Sets the document root for this application * * @param string $value * @return string */ public function set_document_root( $value ) { // some web servers like home.pl and PhpStorm put the document root in "/" or (even weirder) "//". if ( DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR == $value ) { $value = DIRECTORY_SEPARATOR; } if ( DIRECTORY_SEPARATOR !== $value ) { $value = \rtrim( $value, '/\\' ); } return ( $this->_document_root = $value ); } public function add_trailing_slash( $path ) { return \rtrim( $path, '/\\' ) . DIRECTORY_SEPARATOR; } /** * Returns a calculated path to a file. * * This is used *once* by Pro's ecommerce module and cannot be removed just yet. * TODO: remove this eventually. * * @param string $path * @param string|false $module (optional) * @deprecated Use Imagely\NGG\Display\StaticAssets::get_abspath() * @return string */ public function get_abspath( $path, $module = false ) { return StaticPopeAssets::get_abspath( $path, $module ); } /** * Gets the absolute path to a file/directory for a specific Pope product. If the path doesn't exist, then NULL is returned. * * @param string $path * @param string|false $module (optional) * @param bool $relpath (optional) * @param array $search_paths (optional) * @deprecated This is only used by NextGEN Pro's comments module and should not be adopted in new code. * @return string|NULL */ public function find_abspath( $path, $module = false ) { if ( \strpos( $path, '#' ) !== false ) { $parts = \explode( '#', $path ); if ( \count( $parts ) === 2 ) { $path = $parts[1]; $module = $parts[0]; } else { $path = $parts[0]; } } if ( ! $module ) { die( \sprintf( 'find_abspath requires a path and module. Received %s and %s', $path, \strval( $module ) ) ); } $module_dir = \C_Component_Registry::get_instance()->get_module_dir( $module ); $path = \preg_replace( '#^/{1,2}#', '', $path, 1 ); $retval = \path_join( $module_dir, $path ); // Adjust for windows paths. return \wp_normalize_path( $retval ); } /** * @param string $abspath * @return bool */ public function delete( $abspath ) { $retval = false; if ( \file_exists( $abspath ) ) { // Delete single file. if ( \is_file( $abspath ) ) { @\wp_delete_file( $abspath ); } else { // Delete directory. foreach ( \scandir( $abspath ) as $relpath ) { if ( \in_array( $relpath, [ '.', '..' ] ) ) { continue; } $sub_abspath = $this->join_paths( $abspath, $relpath ); $this->delete( $sub_abspath ); } } $retval = ! \file_exists( $abspath ); } return $retval; } /** * Joins multiple path segments together * * @deprecated use path_join() instead when you can * @return string */ public function join_paths() { $segments = []; $retval = []; $params = func_get_args(); $this->_flatten_array( $params, $segments ); foreach ( $segments as $segment ) { $segment = trim( $segment, '/\\' ); $pieces = array_values( \preg_split( '#[/\\\\]#', $segment ) ); $segment = join( DIRECTORY_SEPARATOR, $pieces ); if ( ! $retval ) { $retval = $segment; } elseif ( strpos( $segment, $retval ) !== false ) { $retval = $segment; } else { $retval = $retval . DIRECTORY_SEPARATOR . $segment; } } if ( strpos( $retval, $this->get_document_root() ) !== 0 && ( strtoupper( substr( PHP_OS, 0, 3 ) ) != 'WIN' ) ) { $retval = DIRECTORY_SEPARATOR . trim( $retval, '/\\' ); } // Check for and adjust Windows UNC paths (\\server\share\) for network mounted sites. if ( ( strtoupper( substr( PHP_OS, 0, 3 ) ) == 'WIN' ) && substr( $this->get_document_root(), 0, 2 ) === '\\\\' ) { $retval = '\\\\' . $retval; } return $retval; } protected function _flatten_array( $obj, &$arr ) { if ( \is_array( $obj ) ) { foreach ( $obj as $inner_obj ) { $this->_flatten_array( $inner_obj, $arr ); } } elseif ( $obj ) { $arr[] = $obj; } } /** * Parses the path for a module and filename * * @param string $str * @return array [path => module] */ public function parse_formatted_path( $str ) { $module = false; $path = $str; $parts = explode( '#', $path ); if ( count( $parts ) > 1 ) { $module = array_shift( $parts ); $path = array_shift( $parts ); } return [ $path, $module ]; } /** * Empties a directory of all of its content * * @param string $directory Absolute path * @param bool $recursive Remove files from subdirectories of the cache * @param string $regex (optional) Only remove files matching pattern; '/^.+\.png$/i' will match all .png */ public function flush_directory( $directory, $recursive = true, $regex = null ) { // It is possible that the cache directory has not been created yet. if ( ! is_dir( $directory ) ) { return; } if ( $recursive ) { $directory = new \DirectoryIterator( $directory ); } else { $directory = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $directory ), \RecursiveIteratorIterator::CHILD_FIRST ); } if ( ! is_null( $regex ) ) { $iterator = new \RegexIterator( $directory, $regex, \RecursiveRegexIterator::GET_MATCH ); } else { $iterator = $directory; } foreach ( $iterator as $file ) { if ( $file->isFile() || $file->isLink() ) { @unlink( $file->getPathname() ); } elseif ( $file->isDir() && ! $file->isDot() && $recursive ) { @rmdir( $file->getPathname() ); } } } /** * Flushes cache from all available galleries * * @param array $galleries When provided only the requested galleries' cache is flushed */ public function flush_galleries( $galleries = [] ) { global $wpdb; if ( empty( $galleries ) ) { $galleries = GalleryMapper::get_instance()->find_all(); } foreach ( $galleries as $gallery ) { StorageManager::get_instance()->flush_cache( $gallery ); } // Remove images still in the DB whose gallery no longer exists. $wpdb->query( "DELETE FROM `{$wpdb->nggpictures}` WHERE `galleryid` NOT IN (SELECT `gid` FROM `{$wpdb->nggallery}`)" ); } } Serializable.php000064400000004357150212456520007676 0ustar00 1 ) { // We can't always rely on base64_decode() or json_decode() to return FALSE as their documentation // claims so check if $retval begins with a: as that indicates we have a serialized PHP object. if ( \strpos( $retval, 'a:' ) === 0 ) { if ( self::check_for_serialized_objects( $value ) ) { throw new \Exception( \__( 'NextGEN Gallery will not unserialize data with objects', 'nggallery' ) ); } // Record this for later. $er = \error_reporting( 0 ); // The second parameter was added by PHP 7.0. if ( \version_compare( \phpversion(), '7.0', '>=' ) ) { $retval = \unserialize( $value, [ 'allowed_classes' => false ] ); } else { $retval = \unserialize( $value ); } // Restore error reporting level. \error_reporting( $er ); } else { // We use json_decode() here because PHP's unserialize() is not Unicode safe. $retval = \json_decode( \base64_decode( $retval ), true ); } } } return $retval; } /** * Determines if a string may hold a serialized PHP object * * @param $string * @return bool */ public static function check_for_serialized_objects( $string ) { if ( ! \is_string( $string ) ) { return false; } $string = \trim( $string ); return (bool) \preg_match( '/(O|C):\+?[0-9]+:/is', $string ); } } URL.php000064400000002266150212456520005727 0ustar00has_cap( $capability_name ); } } ThirdPartyCompatibility.php000064400000053123150212456520012107 0ustar00 'NGG_ADD_GALLERY_SLUG', 'NEXTGEN_BASIC_SINGLEPIC_MODULE_NAME' => 'NGG_BASIC_SINGLEPIC', 'NEXTGEN_BASIC_TAG_CLOUD_MODULE_NAME' => 'NGG_BASIC_TAGCLOUD', 'NEXTGEN_DISPLAY_PRIORITY_BASE' => 'NGG_DISPLAY_PRIORITY_BASE', 'NEXTGEN_DISPLAY_PRIORITY_STEP' => 'NGG_DISPLAY_PRIORITY_STEP', 'NEXTGEN_DISPLAY_SETTINGS_SLUG' => 'NGG_DISPLAY_SETTINGS_SLUG', 'NEXTGEN_GALLERY_ATTACH_TO_POST_SLUG' => 'NGG_ATTACH_TO_POST_SLUG', 'NEXTGEN_GALLERY_BASIC_SLIDESHOW' => 'NGG_BASIC_SLIDESHOW', 'NEXTGEN_GALLERY_BASIC_THUMBNAILS' => 'NGG_BASIC_THUMBNAILS', 'NEXTGEN_GALLERY_CHANGE_OPTIONS_CAP' => 'NGG_CHANGE_OPTIONS_CAP', 'NEXTGEN_GALLERY_I18N_DOMAIN' => 'NGG_I18N_DOMAIN', 'NEXTGEN_GALLERY_IMPORT_ROOT' => 'NGG_IMPORT_ROOT', 'NEXTGEN_GALLERY_MODULE_DIR' => 'NGG_MODULE_DIR', 'NEXTGEN_GALLERY_NEXTGEN_BASIC_COMPACT_ALBUM' => 'NGG_BASIC_COMPACT_ALBUM', 'NEXTGEN_GALLERY_NEXTGEN_BASIC_EXTENDED_ALBUM' => 'NGG_BASIC_EXTENDED_ALBUM', 'NEXTGEN_GALLERY_NEXTGEN_BASIC_IMAGEBROWSER' => 'NGG_BASIC_IMAGEBROWSER', 'NEXTGEN_GALLERY_NGGLEGACY_MOD_DIR' => 'NGG_LEGACY_MOD_DIR', 'NEXTGEN_GALLERY_NGGLEGACY_MOD_URL' => 'NGG_LEGACY_MOD_URL', 'NEXTGEN_GALLERY_PLUGIN' => 'NGG_PLUGIN', 'NEXTGEN_GALLERY_PLUGIN_BASENAME' => 'NGG_PLUGIN_BASENAME', 'NEXTGEN_GALLERY_PLUGIN_DIR' => 'NGG_PLUGIN_DIR', 'NEXTGEN_GALLERY_PLUGIN_STARTED_AT' => 'NGG_PLUGIN_STARTED_AT', 'NEXTGEN_GALLERY_PLUGIN_VERSION' => 'NGG_PLUGIN_VERSION', 'NEXTGEN_GALLERY_PRODUCT_DIR' => 'NGG_PRODUCT_DIR', 'NEXTGEN_GALLERY_PROTECT_IMAGE_MOD_STATIC_URL' => 'NGG_PROTUCT_IMAGE_MOD_STATIC_URL', 'NEXTGEN_GALLERY_PROTECT_IMAGE_MOD_URL' => 'NGG_PROTECT_IMAGE_MOD_URL', 'NEXTGEN_GALLERY_TESTS_DIR' => 'NGG_TESTS_DIR', 'NEXTGEN_LIGHTBOX_ADVANCED_OPTIONS_SLUG' => 'NGG_LIGHTBOX_ADVANCED_OPTIONS_SLUG', 'NEXTGEN_LIGHTBOX_OPTIONS_SLUG' => 'NGG_LIGHTBOX_OPTIONS_SLUG', 'NEXTGEN_OTHER_OPTIONS_SLUG' => 'NGG_OTHER_OPTIONS_SLUG', ]; foreach ( $changed_constants as $old => $new ) { if ( defined( $new ) && ! defined( $old ) ) { define( $old, constant( $new ) ); } } } public function register_hooks() { \add_action( 'init', [ $this, 'colorbox' ], PHP_INT_MAX ); \add_action( 'init', [ $this, 'flattr' ], PHP_INT_MAX ); \add_action( 'wp', [ $this, 'bjlazyload' ], PHP_INT_MAX ); \add_action( 'admin_init', [ $this, 'excellent_themes_admin' ], -10 ); \add_action( 'plugins_loaded', [ $this, 'wpml' ], PHP_INT_MAX ); \add_action( 'plugins_loaded', [ $this, 'wpml_translation_management' ], PHP_INT_MAX ); \add_filter( 'wpml_is_redirected', [ $this, 'wpml_is_redirected' ], -10, 3 ); \add_filter( 'headway_gzip', [ $this, 'headway_gzip' ], ( PHP_INT_MAX - 1 ) ); \add_filter( 'ckeditor_external_plugins', [ $this, 'ckeditor_plugins' ], 11 ); \add_filter( 'the_content', [ $this, 'check_weaverii' ], -( PHP_INT_MAX - 2 ) ); \add_action( 'wp', [ $this, 'check_for_jquery_lightbox' ] ); \add_filter( 'get_the_excerpt', [ $this, 'disable_galleries_in_excerpts' ], 1 ); \add_filter( 'get_the_excerpt', [ $this, 'enable_galleries_in_excerpts' ], PHP_INT_MAX - 1 ); \add_action( 'debug_bar_enqueue_scripts', [ $this, 'no_debug_bar' ] ); \add_filter( 'ngg_atp_show_display_type', [ $this, 'atp_check_pro_albums' ], 10, 2 ); \add_filter( 'wpseo_sitemap_urlimages', [ $this, 'add_wpseo_xml_sitemap_images' ], 10, 2 ); \add_filter( 'ngg_pre_delete_unused_term_id', [ $this, 'dont_auto_purge_wpml_terms' ] ); \add_filter( 'rank_math/sitemap/urlimages', [ $this, 'add_rankmath_seo_images' ], 10, 2 ); // Nimble Builder needs special consideration because of our shortcode manager's use of placeholders. \add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_nimble_builder_frontend_resources' ] ); \add_filter( 'ngg_shortcode_placeholder', [ $this, 'nimble_builder_shortcodes' ], 10, 4 ); \add_filter( 'wp_sweep_excluded_taxonomies', function ( $taxonomies ) { $taxonomies[] = 'ngg_tag'; return $taxonomies; } ); if ( $this->is_ngg_page() ) { \add_action( 'admin_enqueue_scripts', [ $this, 'dequeue_spider_calendar_resources' ] ); } // Like WPML, BuddyPress is incompatible with our routing hacks. if ( function_exists( 'buddypress' ) ) { Router::$use_canonical_redirect = false; Router::$use_old_slugs = false; } // WPML fix. if ( in_array( 'SitePress', get_declared_classes(), true ) ) { Router::$use_canonical_redirect = true; Router::$use_old_slugs = false; \add_action( 'template_redirect', [ $this, 'fix_wpml_canonical_redirect' ], 1 ); } add_action( 'the_post', [ $this, 'fix_page_parameter' ] ); } /** * Adds NextGEN images to RankMath when generating page & post sitemaps * * @param array $images * @param int $post_ID * @return array */ public function add_rankmath_seo_images( $images, $post_ID ) { $post = get_post( $post_ID ); preg_match_all( '/' . get_shortcode_regex() . '/', $post->post_content, $matches, PREG_SET_ORDER ); $renderer = DisplayedGalleryRenderer::get_instance(); $storage = StorageManager::get_instance(); $shortcodes = ShortcodesManager::get_instance()->get_shortcodes(); $retval = []; foreach ( $matches as $match ) { // Only process our shortcodes. if ( in_array( $match[2], $shortcodes ) ) { continue; } $params = shortcode_parse_atts( trim( $match[0], '[]' ) ); if ( in_array( $params[0], $shortcodes ) ) { unset( $params[0] ); } $displayed_gallery = $renderer->params_to_displayed_gallery( $params ); // There's no displayed gallery, so no reason to continue. if ( ! $displayed_gallery ) { continue; } foreach ( $displayed_gallery->get_entities() as $entity ) { // Do not start following albums' into their descent into madness. if ( isset( $entity->galdesc ) ) { continue; } $retval[] = [ 'src' => $storage->get_image_url( $entity ) ]; } } return array_merge( $images, $retval ); } /** * This code was originally added to correct a bug in Pro 1.0.10 and was meant to be temporary. However now the * albums pagination relies on this to function correctly, and fixing it properly would require more time than its worth. * * TODO: Remove this once the router and wordpress_routing modules are removed. */ public function fix_page_parameter() { global $post; if ( $post and isset( $post->post_content ) and ( strpos( $post->post_content, '' ) === false ) and ( strpos( $_SERVER['REQUEST_URI'], '/page/' ) !== false ) ) { if ( preg_match( '#/page/(\\d+)#', $_SERVER['REQUEST_URI'], $match ) ) { $_REQUEST['page'] = $match[1]; } } } /** * @param string $placeholder * @param string $shortcode * @param array $params * @param string $inner_content * @return string */ public function nimble_builder_shortcodes( $placeholder, $shortcode, $params, $inner_content ) { if ( ! defined( 'NIMBLE_PLUGIN_FILE' ) ) { return $placeholder; } // Invoke our gallery rendering now. if ( \doing_filter( 'the_nimble_tinymce_module_content' ) ) { $placeholder = Shortcodes::get_instance()->render_shortcode( $shortcode, $params, $inner_content ); } return $placeholder; } /** * @param array $collection */ public function nimble_find_content( $collection ) { if ( ! is_array( $collection ) ) { return; } foreach ( $collection as $item ) { if ( isset( $item['value'] ) && ! empty( $item['value']['text_content'] ) ) { \Imagely\NGG\Display\DisplayManager::enqueue_frontend_resources_for_content( $item['value']['text_content'] ); } if ( ! empty( $item['collection'] ) ) { $this->nimble_find_content( $item['collection'] ); } } } public function enqueue_nimble_builder_frontend_resources() { if ( ! defined( 'NIMBLE_PLUGIN_FILE' ) ) { return; } if ( ! function_exists( '\Nimble\skp_get_skope_id' ) || ! function_exists( '\Nimble\sek_get_skoped_seks' ) || ! function_exists( '\Nimble\sek_sniff_and_decode_richtext' ) ) { return; } // Bail now if called before skope_id is set (before @hook 'wp'). $skope_id = \Nimble\skp_get_skope_id(); if ( empty( $skope_id ) || '_skope_not_set_' === $skope_id ) { return; } $global_sections = \Nimble\sek_get_skoped_seks( NIMBLE_GLOBAL_SKOPE_ID ); $local_sections = \Nimble\sek_get_skoped_seks( $skope_id ); $raw_content = \Nimble\sek_sniff_and_decode_richtext( [ 'local_sections' => $local_sections, 'global_sections' => $global_sections, ] ); foreach ( $raw_content['local_sections'] as $section ) { $this->nimble_find_content( $section ); } foreach ( $raw_content['global_sections'] as $section ) { $this->nimble_find_content( $section ); } } public function is_ngg_page(): bool { return ( \is_admin() && isset( $_REQUEST['page'] ) && false !== strpos( $_REQUEST['page'], 'ngg' ) ); } public function dequeue_spider_calendar_resources() { \remove_filter( 'admin_head', 'spide_ShowTinyMCE' ); } /** * Filter support for WordPress SEO * * @param array $images Provided by WPSEO Filter * @param int $post_id ID Provided by WPSEO Filter * @return array $image List of a displayed galleries entities */ public function add_wpseo_xml_sitemap_images( $images, $post_id ) { $this->wpseo_images = $images; $post = \get_post( $post_id ); // Assign our own shortcode handle. \remove_all_shortcodes(); Shortcodes::add( 'ngg', [ $this, 'wpseo_shortcode_handler' ] ); Shortcodes::add( 'ngg_images', [ $this, 'wpseo_shortcode_handler' ] ); \do_shortcode( $post->post_content ); return $this->wpseo_images; } /** * Processes ngg_images shortcode when WordPress SEO is building sitemaps. Adds images belonging to a * displayed gallery to $this->wpseo_images for the assigned filter method to return. * * @param array $params Array of shortcode parameters * @param null $inner_content */ public function wpseo_shortcode_handler( $params, $inner_content = null ) { $renderer = Renderer::get_instance(); $displayed_gallery = $renderer->params_to_displayed_gallery( $params ); if ( $displayed_gallery ) { $gallery_storage = StorageManager::get_instance(); $settings = Settings::get_instance(); $source = $displayed_gallery->get_source(); if ( in_array( 'image', $source->returns ) ) { foreach ( $displayed_gallery->get_entities() as $image ) { $named_image_size = $settings->get( 'imgAutoResize' ) ? 'full' : 'thumb'; $sitemap_image = [ 'src' => $gallery_storage->get_image_url( $image, $named_image_size ), 'alt' => $image->alttext, 'title' => $image->description ? $image->description : $image->alttext, ]; $this->wpseo_images[] = $sitemap_image; } } } } /** * This style causes problems with Excellent Themes admin settings */ public function excellent_themes_admin() { if ( \is_admin() && ( isset( $_GET['page'] ) && 0 == strpos( $_GET['page'], 'et_' ) ) ) { \wp_deregister_style( 'ngg-jquery-ui' ); } } public function atp_check_pro_albums( $available, $display_type ) { if ( ! defined( 'NGG_PRO_ALBUMS' ) ) { return $available; } if ( in_array( $display_type->name, [ NGG_PRO_LIST_ALBUM, NGG_PRO_GRID_ALBUM ] ) && in_array( 'C_Component_Registry', get_declared_classes(), true ) && \C_Component_Registry::get_instance()->is_module_loaded( NGG_PRO_ALBUMS ) ) { $available = true; } return $available; } public function no_debug_bar() { if ( ATPManager::is_atp_url() ) { \wp_dequeue_script( 'debug-bar-console' ); } } // A lot of routing issues start occuring with WordPress SEO when the routing system is // initialized by the excerpt, and then again from the post content. public function disable_galleries_in_excerpts( $excerpt ) { if ( in_array( 'WPSEO_OpenGraph', get_declared_classes(), true ) ) { ATPManager::$substitute_placeholders = false; } return $excerpt; } public function enable_galleries_in_excerpts( $excerpt ) { if ( in_array( 'WPSEO_OpenGraph', get_declared_classes(), true ) ) { ATPManager::$substitute_placeholders = true; } return $excerpt; } public function fix_wpml_canonical_redirect() { Router::$use_canonical_redirect = false; Router::$use_old_slugs = false; } /** * NGG automatically purges unused terms when managing a gallery, but this also ensnares WPML translations * * @param $term_id * @return bool */ public function dont_auto_purge_wpml_terms( $term_id ) { $args = [ 'element_id' => $term_id, 'element_type' => 'ngg_tag', ]; $term_language_code = \apply_filters( 'wpml_element_language_code', null, $args ); if ( ! empty( $term_language_code ) ) { return false; } else { return $term_id; } } /** * Prevent WPML's parse_query() from conflicting with NGG's pagination & router module controlled endpoints * * @param string $redirect What WPML is send to wp_safe_redirect() * @param int $post_id * @param \WP_Query $q * @return bool|string FALSE prevents a redirect from occurring */ public function wpml_is_redirected( $redirect, $post_id, $q ) { $router = Router::get_instance(); if ( ! $router->serve_request() && $router->has_parameter_segments() ) { return false; } else { return $redirect; } } /** * CKEditor features a custom NextGEN shortcode generator that unfortunately relies on parts of the NextGEN * 1.9x API that has been deprecated in NextGEN 2.0 * * @param $plugins * @return mixed */ public function ckeditor_plugins( $plugins ) { if ( ! in_array( 'add_ckeditor_button', get_declared_classes(), true ) ) { return $plugins; } if ( ! empty( $plugins['nextgen'] ) ) { unset( $plugins['nextgen'] ); } return $plugins; } public function check_for_jquery_lightbox() { // Fix for jQuery Lightbox: http://wordpress.org/plugins/wp-jquery-lightbox/ // jQuery Lightbox tries to modify the content of a post, but it does so before we modify // the content, and therefore it's modifications have no effect on our galleries. if ( function_exists( 'jqlb_autoexpand_rel_wlightbox' ) ) { $settings = Settings::get_instance(); // First, we make it appear that NGG has no lightbox effect enabled. That way we don't any lightbox resources. $settings->delete( 'thumbEffect' ); // We would normally just let the third-party plugin do it's thing, but it's regex doesn't // seem to work on our tags (perhaps because they span multiple of lines or have data attributes) // So instead, we just do what the third-party plugin wants - add the rel attribute. $settings->set( 'thumbCode', "rel='lightbox[%POST_ID%]'" ); } } /** * Weaver II's 'weaver_show_posts' shortcode creates a new wp-query, causing a second round of 'the_content' * filters to apply. This checks for WeaverII and enables all NextGEN shortcodes that would otherwise be left * disabled by our shortcode manager. See https://core.trac.wordpress.org/ticket/17817 for more. * * @param string $content * @return string $content */ public function check_weaverii( $content ) { if ( function_exists( 'weaverii_show_posts_shortcode' ) ) { Shortcodes::get_instance()->activate_all(); } return $content; } /** * WPML assigns an action to 'init' that *may* enqueue some admin-side JS. This JS relies on some inline JS * to be injected that isn't present in ATP so for ATP requests ONLY we disable their action that enqueues * their JS files. */ public function wpml() { if ( ! in_array( 'SitePress', get_declared_classes(), true ) ) { return; } if ( ! ATPManager::is_atp_url() ) { return; } global $wp_filter; if ( empty( $wp_filter['init'][2] ) && empty( $wp_filter['after_setup_theme'][1] ) ) { return; } foreach ( $wp_filter['init'][2] as $id => $filter ) { if ( ! strpos( $id, 'js_load' ) ) { continue; } $object = $filter['function'][0]; if ( is_object( $object ) && get_class( $object ) != 'SitePress' ) { continue; } \remove_action( 'init', [ $object, 'js_load' ], 2 ); } foreach ( $wp_filter['after_setup_theme'][1] as $id => $filter ) { if ( $id !== 'wpml_installer_instance_delegator' ) { continue; } \remove_action( 'after_setup_theme', 'wpml_installer_instance_delegator', 1 ); } } /** * WPML Translation Management has a similar problem to plain ol' WPML */ public function wpml_translation_management() { if ( ! in_array( 'WPML_Translation_Management', get_declared_classes(), true ) ) { return; } if ( ! ATPManager::is_atp_url() ) { return; } global $wp_filter; if ( empty( $wp_filter['init'][10] ) ) { return; } foreach ( $wp_filter['init'][10] as $id => $filter ) { if ( ! strpos( $id, 'init' ) ) { continue; } $object = $filter['function'][0]; if ( is_object( $object ) && get_class( $object ) != 'WPML_Translation_Management' ) { continue; } \remove_action( 'init', [ $object, 'init' ], 10 ); } } /** * Headway themes offer gzip compression, but it causes problems with NextGEN output. Disable that feature while * NextGEN is active. * * @param $option * @return bool */ public function headway_gzip( $option ) { if ( ! in_array( 'HeadwayOption', get_declared_classes(), true ) ) { return $option; } return false; } /** * Colorbox fires a filter (pri=100) to add class attributes to images via a the_content filter. We fire our * shortcodes at PHP_INT_MAX-1 to avoid encoding issues with some themes. Here we move the Colorbox filters * priority to PHP_INT_MAX so that they run after our shortcode text has been replaced with rendered galleries. */ public function colorbox() { if ( ! in_array( 'JQueryColorboxFrontend', get_declared_classes(), true ) ) { return; } global $wp_filter; if ( empty( $wp_filter['the_content'][100] ) ) { return; } foreach ( $wp_filter['the_content'][100] as $id => $filter ) { if ( ! strpos( $id, 'addColorboxGroupIdToImages' ) ) { continue; } $object = $filter['function'][0]; if ( is_object( $object ) && get_class( $object ) != 'JQueryColorboxFrontend' ) { continue; } \remove_filter( 'the_content', [ $object, 'addColorboxGroupIdToImages' ], 100 ); \remove_filter( 'the_excerpt', [ $object, 'addColorboxGroupIdToImages' ], 100 ); \add_filter( 'the_content', [ $object, 'addColorboxGroupIdToImages' ], PHP_INT_MAX ); \add_filter( 'the_excerpt', [ $object, 'addColorboxGroupIdToImages' ], PHP_INT_MAX ); break; } } /** * Flattr fires a filter (pri=32767) on "the_content" that recurses. This causes problems, * see https://core.trac.wordpress.org/ticket/17817 for more information. Moving their filter to PHP_INT_MAX * is enough for us though */ public function flattr() { if ( ! in_array( 'Flattr', get_declared_classes(), true ) ) { return; } global $wp_filter; $level = 32767; if ( empty( $wp_filter['the_content'][ $level ] ) ) { return; } foreach ( $wp_filter['the_content'][ $level ] as $id => $filter ) { if ( ! strpos( $id, 'injectIntoTheContent' ) ) { continue; } $object = $filter['function'][0]; if ( is_object( $object ) && get_class( $object ) != 'Flattr' ) { continue; } \remove_filter( 'the_content', [ $object, 'injectIntoTheContent' ], $level ); \add_filter( 'the_content', [ $object, 'injectIntoTheContent' ], PHP_INT_MAX ); break; } } /** * For the same reasons as Colorbox we move BJ-Lazy-load's filter() method to a later priority so it can access * our rendered galleries. */ public function bjlazyload() { if ( ! in_array( 'BJLL', get_declared_classes(), true ) ) { return; } global $wp_filter; if ( empty( $wp_filter['the_content'][200] ) ) { return; } foreach ( $wp_filter['the_content'][200] as $id => $filter ) { if ( ! strpos( $id, 'filter' ) ) { continue; } $object = $filter['function'][0]; if ( is_object( $object ) && get_class( $object ) != 'BJLL' ) { continue; } \remove_filter( 'the_content', [ $object, 'filter' ], 200 ); \add_filter( 'the_content', [ $object, 'filter' ], PHP_INT_MAX ); break; } \add_filter( 'the_content', [ $this, 'bjlazyload_filter' ], PHP_INT_MAX - 1 ); } /** * BJ-Lazy-load's regex is lazy and doesn't handle multiline search or instances where upgrader =& $upgrader; } } /** * Set the upgrader result and store it as a property in the parent class. * * @since 1.0.0 * * @param object $result The result of the install process. */ public function set_result( $result ) { $this->result = $result; } /** * Empty out the header of its HTML content and only check to see if it has * been performed or not. * * @since 1.0.0 */ public function header() {} /** * Empty out the footer of its HTML contents. * * @since 1.0.0 */ public function footer() {} /** * Instead of outputting HTML for errors, json_encode the errors and send them * back to the Ajax script for processing. * * @since 1.0.0 * * @param array $errors Array of errors with the install process. */ public function error( $errors ) { if ( ! empty( $errors ) ) { echo wp_json_encode( [ 'error' => __( 'There was an error installing the addon. Please try again.', 'nggallery' ) ] ); die; } } /** * Empty out the feedback method to prevent outputting HTML strings as the install * is progressing. * * @since 1.0.0 * * @param string $string The feedback string. * @param array ...$args The args. */ public function feedback( $string, ...$args ) {} // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.stringFound } Transient.php000064400000016464150212456520007241 0ustar00_groups = get_option( 'ngg_transient_groups', [ '__counter' => 1 ] ); if ( $_wp_using_ext_object_cache ) { $this->_tracker = get_option( 'photocrati_cache_tracker', [] ); } register_shutdown_function( [ $this, '_update_tracker' ] ); } public function delete_tracked( $group = null ) { global $_wp_using_ext_object_cache; if ( $_wp_using_ext_object_cache ) { if ( $group ) { if ( is_array( $this->_tracker ) && isset( $this->_tracker[ $this->get_group_id( $group ) ] ) ) { foreach ( $this->_tracker[ $this->get_group_id( $group ) ] as $key ) { delete_transient( $this->get_group_id( $group ) . '__' . $key ); } unset( $this->_tracker[ $this->get_group_id( $group ) ] ); } } else { foreach ( $this->_groups as $group => $data ) { $this->delete_tracked( $group ); } } } } /** * Despite the underscore prefix this cannot be marked protected: it is used by register_shutdown_function() */ public function _update_tracker() { global $_wp_using_ext_object_cache; if ( $_wp_using_ext_object_cache ) { $current_value = get_option( 'photocrati_cache_tracker', [] ); if ( $current_value !== $this->_tracker ) { update_option( 'photocrati_cache_tracker', $this->_tracker, 'no' ); } } } public function add_group( $group_or_groups ) { $updated = false; $groups = is_array( $group_or_groups ) ? $group_or_groups : [ $group_or_groups ]; // Initialize the groups array if it doesn't exist or is not an array. // If the 'ngg_transient_groups' option is set and is not an array, this could cause fatal error. if( !is_array( $this->_groups ) ) { $this->_groups = []; } foreach ( $groups as $group ) { if ( ! isset( $this->_groups[ $group ] ) ) { $id = $this->_groups['__counter'] += 1; $this->_groups[ $group ] = [ 'id' => $id, 'enabled' => true, ]; $updated = true; } } if ( $updated ) { update_option( 'ngg_transient_groups', $this->_groups ); } } public function get_group_id( $group_name ) { $this->add_group( $group_name ); return $this->_groups[ $group_name ]['id']; } public function generate_key( $group, $params = [] ) { if ( is_object( $params ) ) { $params = (array) $params; } if ( is_array( $params ) ) { foreach ( $params as &$param ) { $param = @json_encode( $param ); } $params = implode( '', $params ); } return $this->get_group_id( $group ) . '__' . str_replace( '-', '_', crc32( $params ) ); } public function get( $key, $default = null, $lookup = null ) { $retval = $default; if ( is_null( $lookup ) && defined( 'PHOTOCRATI_CACHE' ) ) { $lookup = PHOTOCRATI_CACHE; } if ( $lookup ) { $retval = json_decode( get_transient( $key ) ); if ( is_object( $retval ) ) { $retval = (array) $retval; } if ( is_null( $retval ) ) { $retval = $default; } } return $retval; } protected function _track_key( $key ) { global $_wp_using_ext_object_cache; if ( $_wp_using_ext_object_cache ) { $parts = explode( '__', $key ); $group = $parts[0]; $id = $parts[1]; if ( ! isset( $this->_tracker[ $group ] ) ) { $this->_tracker[ $group ] = []; } if ( ! in_array( $id, $this->_tracker[ $group ] ) ) { $this->_tracker[ $group ][] = $id; } } } public function set( $key, $value, $ttl = 0 ) { $retval = false; $enabled = true; if ( defined( 'PHOTOCRATI_CACHE' ) ) { $enabled = PHOTOCRATI_CACHE; } if ( defined( 'PHOTOCRATI_CACHE_TTL' ) && ! $ttl ) { $ttl = PHOTOCRATI_CACHE_TTL; } if ( $enabled ) { $retval = set_transient( $key, json_encode( $value ), $ttl ); if ( $retval ) { $this->_track_key( $key ); } } return $retval; } public function delete( $key ) { return delete_transient( $key ); } /** * Clears all (or only expired) transients managed by this utility * * @param string $group Group name to purge * @param bool $expired Whether to clear all transients (FALSE) or to clear expired transients (TRUE) */ public function clear( $group = null, $expired = false ) { if ( $group === '__counter' ) { return; } if ( is_string( $group ) && ! empty( $group ) ) { global $wpdb; // A little query building is necessary here.. // Clear transients for "the" site or for the current multisite instance. $expired_sql = ''; $params = [ $wpdb->esc_like( '_transient_' ) . '%', '%' . $wpdb->esc_like( "{$this->get_group_id($group)}__" ) . '%', $wpdb->esc_like( '_transient_timeout_' ) . '%', ]; if ( $expired ) { $params[] = time(); $expired_sql = $expired ? 'AND b.option_value < %d' : ''; } $sql = "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b WHERE a.option_name LIKE %s AND a.option_name LIKE %s AND a.option_name NOT LIKE %s AND b.option_name = CONCAT('_transient_timeout_', SUBSTRING(a.option_name, 12)) {$expired_sql}"; // This is a false positive. // // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( $wpdb->prepare( $sql, $params ) ); // Clear transients for the main site of a multisite network. if ( is_main_site() && is_main_network() ) { $expired_sql = ''; $params = [ $wpdb->esc_like( '_site_transient_' ) . '%', '%' . $wpdb->esc_like( "{$this->get_group_id($group)}__" ) . '%', $wpdb->esc_like( '_site_transient_timeout_' ) . '%', ]; if ( $expired ) { $params[] = time(); $expired_sql = $expired ? 'AND b.option_value < %d' : ''; } $sql = "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b WHERE a.option_name LIKE %s AND a.option_name LIKE %s AND a.option_name NOT LIKE %s AND b.option_name = CONCAT('_site_transient_timeout_', SUBSTRING(a.option_name, 17)) {$expired_sql}"; // This is a false positive. // // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( $wpdb->prepare( $sql, $params ) ); } if ( $expired ) { $this->delete_tracked( $group ); } } else { foreach ( $this->_groups as $name => $params ) { $this->clear( $name, $expired ); } } } public static function update( $key, $value, $ttl = null ) { return self::get_instance()->set( $key, $value, $ttl ); } public static function fetch( $key, $default = null ) { return self::get_instance()->get( $key, $default ); } public static function flush( $group = null ) { self::get_instance()->clear( $group ); } public static function flush_expired( $group = null ) { self::get_instance()->clear( $group, true ); } public static function create_key( $group, $params = [] ) { return self::get_instance()->generate_key( $group, $params ); } } RoutingApp.php000064400000112441150212456520007352 0ustar00_settings = $this->get_routing_settings(); $this->context = $context; } public function get_routing_settings() { $settings = Settings::get_instance(); $object = new \stdClass(); $object->router_param_separator = $settings->get( 'router_param_separator', '--' ); $object->router_param_slug = $settings->get( 'router_param_slug', 'nggallery' ); $object->router_param_prefix = $settings->get( 'router_param_prefix', '' ); return $object; } public static function get_instance( $context = false ) { if ( ! isset( self::$_instances[ $context ] ) ) { self::$_instances[ $context ] = new RoutingApp( $context ); } return self::$_instances[ $context ]; } /** * Creates a new route endpoint with the assigned handler * * @param string[] $routes URL to route, eg /page/{page}/ * @param array $handler Formatted array */ public function route( $routes, $handler ) { // ensure that the routing patterns array exists. if ( ! is_array( $this->_routing_patterns ) ) { $this->_routing_patterns = []; } if ( ! is_array( $routes ) ) { $routes = [ $routes ]; } // fetch all routing patterns. $patterns = $this->_routing_patterns; foreach ( $routes as $route ) { // add the routing pattern. $patterns[ $this->_route_to_regex( $route ) ] = $handler; } // update routing patterns. $this->_routing_patterns = $patterns; } /** * Handles internal url rewriting with optional HTTP redirection, * * @param string $src Original URL * @param string $dst Destination URL * @param bool $redirect FALSE for internal handling, otherwise the HTTP code to send * @param bool $stop */ public function rewrite( $src, $dst, $redirect = false, $stop = false ) { // ensure that rewrite patterns array exists. if ( ! is_array( $this->_rewrite_patterns ) ) { $this->_rewrite_patterns = []; } // fetch all rewrite patterns. $patterns = $this->_rewrite_patterns; // Assign rewrite definition. $definition = [ 'dst' => $dst, 'redirect' => $redirect, 'stop' => $stop, ]; // We treat wildcards much differently than normal rewrites. if ( preg_match( '/\\{[\\.\\\\*]/', $src ) ) { $pattern = str_replace( '{*}', '(.*?)', $src ); $pattern = str_replace( '{.*}', '(.*?)', $pattern ); $pattern = str_replace( '{\\w}', '([^/]*)', $pattern ); $pattern = str_replace( '{\\d}', '(\\d*)', $pattern ); $src = '#' . ( strpos( $src, '/' ) === 0 ? '^' : '' ) . $pattern . '/?$#'; $definition['wildcards'] = true; } else { // Normal rewrite. $src = $this->_route_to_regex( $src ); } // add the rewrite pattern. $patterns[ $src ] = $definition; // update rewrite patterns. $this->_rewrite_patterns = $patterns; } /** * Gets an instance of the router * * @return Router */ public function get_router() { return Router::get_instance(); } public function get_app_url( $request_uri = false, $with_qs = false ) { return $this->get_router()->get_url( $this->get_app_uri( $request_uri ), $with_qs ); } public function get_routed_url( $with_qs = true ) { return $this->get_app_url( false, $with_qs ); } public function get_app_uri( $request_uri = false ) { if ( ! $request_uri ) { $request_uri = $this->get_app_request_uri(); } return $this->join_paths( $this->context, $request_uri ); } public function get_app_request_uri() { $retval = false; if ( $this->_request_uri ) { $retval = $this->_request_uri; } elseif ( ( $retval = $this->does_app_serve_request() ) ) { if ( strpos( $retval, '/' ) !== 0 ) { $retval = '/' . $retval; } $this->set_app_request_uri( $retval ); } return $retval; } /** * Sets the application request uri * * @param string $uri */ public function set_app_request_uri( $uri ) { $this->_request_uri = $uri; } /** * Gets the application's routing regex pattern * * @return string */ public function get_app_routing_pattern() { return $this->_route_to_regex( $this->context ); } /** * Determines whether this app serves the request * * @return boolean|string */ public function does_app_serve_request() { $retval = false; $request_uri = $this->get_router()->get_request_uri( true ); // Is the context present in the uri? if ( ( $index = strpos( $request_uri, $this->context ) ) !== false ) { $starts_with_slash = strpos( $this->context, '/' ) === 0; if ( ( $starts_with_slash && $index === 0 ) or ( ! $starts_with_slash ) ) { $regex = implode( '', [ '#', ( $starts_with_slash ? '^' : '' ), preg_quote( $this->context, '#' ), '#', ] ); $retval = preg_replace( $regex, '', $request_uri ); if ( ! $retval ) { $retval = '/'; } if ( strpos( $retval, '/' ) !== 0 ) { $retval = '/' . $retval; } if ( substr( $retval, -1 ) != '/' ) { $retval = $retval . '/'; } } } return $retval; } /** * Performs the url rewriting routines. Returns the HTTP status code used to * redirect, if we're to do so. Otherwise FALSE * * @return int|bool */ public function do_rewrites( $request_uri = false ) { $redirect = false; static $stop_processing = false; // Get the request uri if not provided, if provided decode it. if ( ! $request_uri ) { $request_uri = $this->get_app_request_uri(); } else { $request_uri = urldecode( $request_uri ); } // ensure that rewrite patterns array exists. if ( ! is_array( $this->_rewrite_patterns ) ) { $this->_rewrite_patterns = []; } // Process each rewrite rule // start rewriting urls. if ( ! $stop_processing ) { foreach ( $this->_rewrite_patterns as $pattern => $details ) { // Remove this pattern from future processing for this request. unset( $this->_rewrite_patterns[ $pattern ] ); // Wildcards are processed much differently. if ( isset( $details['wildcards'] ) && $details['wildcards'] ) { if ( preg_match( $pattern, $request_uri, $matches ) ) { foreach ( $matches as $index => $match ) { if ( $index == 0 ) { $request_uri = str_replace( $match, $details['dst'], $request_uri ); } if ( $index > 0 ) { $request_uri = str_replace( "{{$index}}", $match, $request_uri ); } } // Set the redirect flag if we're to do so. if ( isset( $details['redirect'] ) && $details['redirect'] ) { $redirect = $details['redirect'] === true ? 302 : intval( $details['redirect'] ); break; } // Stop processing rewrite patterns? if ( $details['stop'] ) { $stop_processing = true; } } } // Normal rewrite pattern. elseif ( preg_match_all( $pattern, $request_uri, $matches, PREG_SET_ORDER ) ) { // Assign new request URI. $request_uri = $details['dst']; // Substitute placeholders. foreach ( $matches as $match ) { if ( $redirect ) { break; } foreach ( $match as $key => $val ) { // If we have a placeholder that needs swapped, swap // it now. if ( is_numeric( $key ) ) { continue; } $request_uri = str_replace( "{{$key}}", $val, $request_uri ); } // Set the redirect flag if we're to do so. if ( isset( $details['redirect'] ) && $details['redirect'] ) { $redirect = $details['redirect'] === true ? 302 : intval( $details['redirect'] ); break; } } } if ( $stop_processing ) { break; } } } // Cache all known data about the application request. $this->set_app_request_uri( $request_uri ); $this->get_router()->set_routed_app( $this ); return $redirect; } /** * Determines if the current routing app meets our requirements and serves them * * @return bool */ public function serve_request() { $served = false; // ensure that the routing patterns array exists. if ( ! is_array( $this->_routing_patterns ) ) { $this->_routing_patterns = []; } // if the application root matches, then we'll try to route the request. if ( ( $request_uri = $this->get_app_request_uri() ) ) { // Perform URL rewrites. $redirect = $this->do_rewrites( $request_uri ); // Are we to perform a redirect? if ( $redirect ) { $this->execute_route_handler( $this->parse_route_handler( $redirect ) ); } else { // Handle routed endpoints. foreach ( $this->_routing_patterns as $pattern => $handler ) { if ( preg_match( $pattern, $this->get_app_request_uri(), $matches ) ) { $served = true; // Add placeholder parameters. foreach ( $matches as $key => $value ) { if ( is_numeric( $key ) ) { continue; } $this->set_parameter_value( $key, $value, null ); } // If a handler is attached to the route, execute it. A // handler can be // - FALSE, meaning don't do any post-processing to the route // - A string, such as controller#action // - An array: array( // 'controller' => 'I_Test_Controller', // 'action' => 'index', // 'context' => 'all', (optional) // 'method' => array('GET') (optional) // ). if ( $handler && $handler = $this->parse_route_handler( $handler ) ) { // Is this handler for the current HTTP request method? if ( isset( $handler['method'] ) ) { if ( ! is_array( $handler['method'] ) ) { $handler['$method'] = [ $handler['method'] ]; } if ( in_array( $this->get_router()->get_request_method(), $handler['method'] ) ) { $this->execute_route_handler( $handler ); } } // This handler is for all request methods. else { $this->execute_route_handler( $handler ); } } elseif ( ! $handler ) { $this->passthru(); } } } } } return $served; } /** * Executes an action of a particular controller * * @param array $handler */ public function execute_route_handler( $handler ) { // qTranslate requires we disable "Hide Untranslated Content" during routed app requests like // photocrati-ajax, when uploading new images, or retrieving dynamically altered (watermarked) images. if ( ! empty( $GLOBALS['q_config'] ) && defined( 'QTRANS_INIT' ) ) { global $q_config; $q_config['hide_untranslated'] = 0; } // Get action. $action = $handler['action']; if ( class_exists( $handler['controller'] ) ) { $controller = new $handler['controller'](); } // TODO: Remove when Pro's minimum supported version supports v1 of the POPE removal compat. elseif ( class_exists( '\C_Component_Registry' ) ) { $controller = \C_Component_Registry::get_instance()->get_utility( $handler['controller'], $handler['context'] ); } // Call action. $controller->$action(); exit(); } /** * Parses the route handler * * @param mixed $handler * @return array */ public function parse_route_handler( $handler ) { if ( is_string( $handler ) ) { $handler = array_combine( [ 'controller', 'action' ], explode( '#', $handler ) ); } if ( ! isset( $handler['context'] ) ) { $handler['context'] = false; } if ( strpos( $handler['action'], '_action' ) === false ) { $handler['action'] .= '_action'; } return $handler; } /** * Converts the route to the regex * * @param string $route * @return string */ public function _route_to_regex( $route ) { // Get the settings manager. $settings = $this->_settings; $param_slug = $settings->router_param_slug; // convert route to RegEx pattern. $route_regex = preg_quote( str_replace( [ '{', '}' ], [ '~', '~' ], $route ), '#' ); // Wrap the route. $route_regex = '(' . $route_regex . ')'; // If the route starts with a slash, then it must appear at the beginning // of a request uri. if ( strpos( $route, '/' ) === 0 ) { $route_regex = '^' . $route_regex; } // If the route is not /, and perhaps /foo, then we need to optionally // look for a trailing slash as well. if ( $route != '/' ) { $route_regex .= '/?'; } // If parameters come after a slug, it might appear as well. if ( $param_slug ) { $route_regex .= '(' . preg_quote( $param_slug, '#' ) . '/)?'; } // Parameter might follow the request uri. $route_regex .= '(/?([^/]+\-\-)?[^/]+\-\-[^/]+/?){0,}'; // Create the regex. $route_regex = '#' . $route_regex . '/?$#i'; // convert placeholders to regex as well. return preg_replace( '/~([^~]+)~/i', ( $param_slug ? '(' . preg_quote( $param_slug, '#' ) . '\K)?' : '' ) . '(?P<\1>[^/]+)/?', $route_regex ); } /** * Gets a request parameter from either the request uri or querystring. * * This method takes into consideration the values of the router_param_prefix and router_param_separator settings * when searching for the parameter. * * Parameter can take on the following forms: * /key--value * /[MVC_PARAM_PREFIX]key--value * /[MVC_PARAM_PREFIX]-key--value * /[MVC_PARAM_PREFIX]_key--value * /id--key--value * /id--[MVC_PARAM_PREFIX]key--value * /id--[MVC_PARAM_PREFIX]-key--value * /id--[MVC_PARAM_PREFIX]_key--value * * @param string $key * @param mixed $id * @param mixed $default * @return mixed */ public function get_parameter( $key, $id = null, $default = null, $segment = false, $url = false ) { $retval = $default; $settings = $this->_settings; $quoted_key = preg_quote( $key, '#' ); $id = $id ? preg_quote( $id, '#' ) : '[^/]+'; $param_prefix = preg_quote( $settings->router_param_prefix, '#' ); $param_sep = preg_quote( $settings->router_param_separator, '#' ); $param_regex = "#/((?P{$id}){$param_sep})?({$param_prefix}[-_]?)?{$quoted_key}{$param_sep}(?P[^/\?]+)/?#i"; $found = false; $sources = $url ? [ 'custom' => $url ] : $this->get_parameter_sources(); foreach ( $sources as $source_name => $source ) { if ( preg_match( $param_regex, $source, $matches ) ) { if ( $segment ) { $retval = [ 'segment' => $matches[0], 'source' => $source_name, ]; } else { $retval = $this->recursive_stripslashes( $matches['value'] ); } $found = true; break; } } // Lastly, check the $_REQUEST. if ( ! $found && ! $url && isset( $_REQUEST[ $key ] ) ) { $found = true; $retval = $this->recursive_stripslashes( $_REQUEST[ $key ] ); } if ( ! $found && isset( $_SERVER['REQUEST_URI'] ) ) { $params = []; $parsed = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY ); if ( is_string( $parsed ) ) { parse_str( $parsed, $params ); } if ( isset( $params[ $key ] ) ) { $retval = $this->recursive_stripslashes( $params[ $key ] ); } } return $retval; } /** * Alias for remove_parameter() * * @param string $key * @param mixed $id * @return string */ public function remove_param( $key, $id = null, $url = false ) { return $this->remove_parameter( $key, $id, $url ); } /** * Adds a parameter to the application's request URI * * @param string $key * @param mixed $value * @param mixed $id (optional) * @param bool|string $use_prefix (optional) * @return string */ public function add_parameter_to_app_request_uri( $key, $value, $id = null, $use_prefix = false ) { $settings = $this->_settings; $param_slug = $settings->router_param_slug; $uri = $this->get_app_request_uri(); $parts = [ $uri ]; if ( $param_slug && strpos( $uri, $param_slug ) === false ) { $parts[] = $param_slug; } $parts[] = $this->create_parameter_segment( $key, $value, $id, $use_prefix ); $this->set_app_request_uri( $this->join_paths( $parts ) ); return $this->get_app_request_uri(); } /** * Alias for set_parameter_value * * @param string $key * @param mixed $value * @param mixed $id (optional) * @param bool $use_prefix (optional) * @param bool|string $url (optional) * @return string */ public function set_parameter( $key, $value, $id = null, $use_prefix = false, $url = false ) { return $this->set_parameter_value( $key, $value, $id, $use_prefix, $url ); } /** * Alias for set_parameter_value * * @param string $key * @param mixed $value * @param mixed $id (optional) * @param bool $use_prefix (optional) * @param bool|string $url (optional) * @return string */ public function set_param( $key, $value, $id = null, $use_prefix = false, $url = false ) { return $this->set_parameter_value( $key, $value, $id, $use_prefix, $url ); } /** * Gets a parameter's matching URI segment * * @param string $key * @param mixed $id * @param mixed $url * @return mixed */ public function get_parameter_segment( $key, $id = null, $url = false ) { return $this->get_parameter( $key, $id, null, true, $url ); } /** * Gets sources used for parsing and extracting parameters * * @return array */ public function get_parameter_sources() { return [ 'querystring' => $this->get_formatted_querystring(), 'request_uri' => $this->get_app_request_uri(), ]; } public function get_formatted_querystring() { $retval = '/' . $this->get_router()->get_querystring(); $settings = $this->_settings; $retval = str_replace( [ '&', '=' ], [ '/', $settings->router_param_separator ], $retval ); return $retval; } public function has_parameter_segments() { $retval = false; $settings = $this->_settings; $request_uri = $this->get_app_request_uri(); $sep = preg_quote( $settings->router_param_separator, '#' ); // If we detect the MVC_PARAM_SLUG, then we assume that we have parameters. if ( $settings->router_param_slug && strpos( $request_uri, '/' . $settings->router_param_slug . '/' ) !== false ) { $retval = true; } // If the above didn't pass, then we try finding parameters in our // desired format. if ( ! $retval ) { $regex = implode( '', [ '#', $settings->router_param_slug ? '/' . preg_quote( $settings->router_param_slug, '#' ) . '/?' : '', "(/?([^/]+{$sep})?[^/]+{$sep}[^/]+/?){0,}", '$#', ] ); $retval = preg_match( $regex, $request_uri ); } return $retval; } /** * Recursively calls stripslashes() on strings, arrays, and objects * * @param mixed $value Value to be processed * @return mixed Resulting value */ public function recursive_stripslashes( $value ) { if ( is_string( $value ) ) { $value = stripslashes( $value ); } elseif ( is_array( $value ) ) { foreach ( $value as &$tmp ) { $tmp = $this->recursive_stripslashes( $tmp ); } } elseif ( is_object( $value ) ) { foreach ( get_object_vars( $value ) as $key => $data ) { $value->{$key} = $this->recursive_stripslashes( $data ); } } return $value; } public function passthru() { $router = Router::get_instance(); $_SERVER['NGG_ORIG_REQUEST_URI'] = $_SERVER['REQUEST_URI']; $base_parts = parse_url( $router->get_base_url( 'root' ) ); $new_request_uri = $router->join_paths( ( ! empty( $base_parts['path'] ) ? $base_parts['path'] : '' ), $this->strip_param_segments( $router->get_request_uri() ) ); $new_request_uri = str_replace( 'index.php/index.php', 'index.php', $new_request_uri ); // Handle possible incompatibility with 3rd party plugins manipulating the query as well: WPML in particular // can lead to our $new_request_uri here becoming index.php/en/index.php: remove this double index.php. $uri_array = explode( '/', $new_request_uri ); if ( ! empty( $uri_array ) && count( $uri_array ) >= 2 && reset( $uri_array ) == 'index.php' && end( $uri_array ) == 'index.php' ) { array_shift( $uri_array ); $new_request_uri = implode( '/', $uri_array ); } $_SERVER['UNENCODED_URL'] = $_SERVER['HTTP_X_ORIGINAL_URL'] = $_SERVER['REQUEST_URI'] = '/' . trailingslashit( $new_request_uri ); if ( isset( $_SERVER['PATH_INFO'] ) ) { $_SERVER['ORIG_PATH_INFO'] = $_SERVER['PATH_INFO']; unset( $_SERVER['PATH_INFO'] ); } } public function parse_url( $url ) { $parts = parse_url( $url ); if ( ! isset( $parts['path'] ) ) { $parts['path'] = '/'; } if ( ! isset( $parts['query'] ) ) { $parts['query'] = ''; } return $parts; } /** * Adds the post permalink to the url, if it isn't already present. * * The generated_url could look like: * http://localhost/dir/nggallery/show/slideshow * * @param $generated_url * @return mixed */ public function add_post_permalink_to_url( $generated_url ) { if ( ! apply_filters( 'ngg_wprouting_add_post_permalink', true ) ) { return $generated_url; } global $multipage, $page; $base_url = $this->get_router()->get_base_url( 'home' ); $settings = Settings::get_instance(); if ( strlen( $generated_url ) < 2 ) { $generated_url = $base_url; } $original_url = $generated_url; $generated_parts = explode( $settings->get( 'router_param_slug', 'nggallery' ), $generated_url ); $generated_url = $generated_parts[0]; $ngg_parameters = '/'; if ( isset( $generated_parts[1] ) ) { $parts = explode( '?', $generated_parts[1] ); $ngg_parameters = array_shift( $parts ); } $post_permalink = get_permalink( isset( $_REQUEST['p'] ) ? $_REQUEST['p'] : 0 ); if ( $post_permalink == '/' ) { $post_permalink = $base_url; } // Trailing slash all of the urls. $original_url = trailingslashit( $original_url ); $post_permalink = trailingslashit( $post_permalink ); $generated_url = trailingslashit( $generated_url ); // Ensure that /page/2/ links to /page/2/nggallery/page/4 rather than /nggallery/page/4/ when our paginated // galleries are displayed on posts paginated through the page break block. if ( $multipage && $page >= 2 ) { $post_permalink = $post_permalink . $page; } // We need to determine if the generated url and the post permalink TRULY differ. If they // differ, then we'll return post_permalink + nggallery parameters appended. Otherwise, we'll // just return the generated url. $generated_url = str_replace( $base_url, home_url(), $generated_url ); $generated_parts = $this->parse_url( $generated_url ); $post_parts = $this->parse_url( $post_permalink ); $generated_parts['path'] = trailingslashit( $generated_parts['path'] ); if ( isset( $generated_parts['query'] ) ) { $generated_parts['query'] = untrailingslashit( $generated_parts['query'] ); } $post_parts['path'] = trailingslashit( $post_parts['path'] ); if ( isset( $post_parts['query'] ) ) { $post_parts['query'] = untrailingslashit( $post_parts['query'] ); } $generated_url = $this->construct_url_from_parts( $generated_parts ); $post_permalink = $this->construct_url_from_parts( $post_parts ); // No change required... if ( $generated_url == $post_permalink ) { $generated_url = $original_url; // Ensure that the generated url has the real base url for default permalinks. if ( strpos( $generated_url, home_url() ) !== false && strpos( $generated_url, $base_url ) === false ) { $generated_url = str_replace( home_url(), $base_url, $generated_url ); } } else { // The post permalink differs from the generated url. $post_permalink = str_replace( home_url(), $base_url, $post_permalink ); $post_parts = $this->parse_url( $post_permalink ); $post_parts['path'] = $this->join_paths( $post_parts['path'], $settings->get( 'router_param_slug', 'nggallery' ), $ngg_parameters ); $post_parts['path'] = str_replace( 'index.php/index.php', 'index.php', $post_parts['path'] ); // incase permalink_structure contains index.php. if ( ! empty( $generated_parts['query'] ) && empty( $post_parts['query'] ) ) { $post_parts['query'] = $generated_parts['query']; } $generated_url = $this->construct_url_from_parts( $post_parts ); } return $generated_url; } public function join_paths() { $args = func_get_args(); $parts = $this->_flatten_array( $args ); foreach ( $parts as &$part ) { $part = trim( str_replace( '\\', '/', $part ), '/' ); } return implode( '/', $parts ); } /** * Removes a segment from a url * * @param string $segment * @param string $url * @return string */ public function remove_url_segment( $segment, $url ) { $retval = $url; $parts = parse_url( $url ); // If the url has a path, then we can remove a segment. if ( isset( $parts['path'] ) && $segment != '/' ) { if ( substr( $segment, -1 ) == '/' ) { $segment = substr( $segment, -1 ); } $segment = preg_quote( $segment, '#' ); if ( preg_match( "#{$segment}#", $parts['path'], $matches ) ) { $parts['path'] = str_replace( '//', '/', str_replace( $matches[0], '', $parts['path'] ) ); $retval = $this->construct_url_from_parts( $parts ); } } return $retval; } /** * Flattens an array of arrays to a single array * * @param array $array * @param array $parent (optional) * @param bool $exclude_duplicates (optional - defaults to TRUE) * @return array */ public function _flatten_array( $array, $parent = null, $exclude_duplicates = true ) { if ( is_array( $array ) ) { // We're to add each element to the parent array. if ( $parent ) { foreach ( $array as $index => $element ) { foreach ( $this->_flatten_array( $array ) as $sub_element ) { if ( $exclude_duplicates ) { if ( ! in_array( $sub_element, $parent ) ) { $parent[] = $sub_element; } } else { $parent[] = $sub_element; } } } $array = $parent; } // We're starting the process.. else { $index = 0; while ( isset( $array[ $index ] ) ) { $element = $array[ $index ]; if ( is_array( $element ) ) { $array = $this->_flatten_array( $element, $array ); unset( $array[ $index ] ); } $index += 1; } $array = array_values( $array ); } } else { $array = [ $array ]; } return $array; } /** * Constructs a url from individual parts, created by parse_url * * @param array $parts * @return string */ public function construct_url_from_parts( $parts ) { // let relative paths be relative, and full paths full. $prefix = ''; if ( ! empty( $parts['scheme'] ) && ! empty( $parts['host'] ) ) { $prefix = $parts['scheme'] . '://' . $parts['host']; if ( ! empty( $parts['port'] ) ) { $prefix .= ':' . $parts['port']; } } $retval = $this->join_paths( $prefix, isset( $parts['path'] ) ? str_replace( '//', '/', trailingslashit( $parts['path'] ) ) : '' ); if ( isset( $parts['query'] ) && $parts['query'] ) { $retval .= untrailingslashit( "?{$parts['query']}" ); } return $retval; } /** * Returns the request uri with the parameter segments stripped * * @param string $request_uri * @return string */ public function strip_param_segments( $request_uri, $remove_slug = true ) { $retval = $request_uri ? $request_uri : '/'; $settings = Settings::get_instance(); $sep = preg_quote( $settings->get( 'router_param_separator', '--' ), '#' ); $param_regex = "#((?P\w+){$sep})?(?\w+){$sep}(?P.+)/?$#"; $slug = $settings->get( 'router_param_slug', 'nggallery' ) && $remove_slug ? '/' . preg_quote( $settings->get( 'router_param_slug', 'nggallery' ), '#' ) : ''; $slug_regex = '#' . $slug . '/?$#'; // Remove all parameters. while ( @preg_match( $param_regex, $retval, $matches ) ) { $match_regex = '#' . preg_quote( array_shift( $matches ), '#' ) . '$#'; $retval = preg_replace( $match_regex, '', $retval ); } // Remove the slug or trailing slash. if ( @preg_match( $slug_regex, $retval, $matches ) ) { $match_regex = '#' . preg_quote( array_shift( $matches ), '#' ) . '$#'; $retval = preg_replace( $match_regex, '', $retval ); } // If there's a slug, we can assume everything after is a parameter, // even if it's not in our desired format. $retval = preg_replace( '#' . $slug . '.*$#', '', $retval ); if ( ! $retval ) { $retval = '/'; } return $retval; } /** * Creates a parameter segment * * @param string $key * @param mixed $value * @param mixed $id * @return string */ public function create_parameter_segment( $key, $value, $id = null, $use_prefix = false ) { if ( $key === 'nggpage' ) { return 'page/' . $value; } elseif ( $key === 'album' ) { return $value; } elseif ( $key === 'gallery' ) { return $value; } elseif ( $key === 'pid' ) { return "image/{$value}"; } elseif ( $key === 'gallerytag' ) { return 'tags/' . $value; } if ( $key == 'show' ) { if ( $value === NGG_BASIC_SLIDESHOW ) { $value = 'slideshow'; } elseif ( $value == NGG_BASIC_THUMBNAILS ) { $value = 'thumbnails'; } elseif ( $value == NGG_BASIC_IMAGEBROWSER ) { $value = 'imagebrowser'; } return $value; } $settings = $this->_settings; if ( $use_prefix ) { $key = $settings->router_param_prefix . $key; } if ( $value === true ) { $value = 1; } elseif ( $value === false ) { $value = 0; // null and false values. } $retval = $key . $settings->router_param_separator . $value; if ( $id ) { $retval = $id . $settings->router_param_separator . $retval; } return $retval; } /** * Removes a parameter from the querystring and application request URI and returns the full application URL * * @param string $key * @param mixed $id * @return string|array|float|int */ public function remove_parameter( $key, $id = null, $url = false ) { $retval = $url; $settings = $this->_settings; $param_sep = $settings->router_param_separator; $param_prefix = $settings->router_param_prefix ? preg_quote( $settings->router_param_prefix, '#' ) : ''; $param_slug = $settings->router_param_slug ? preg_quote( $settings->router_param_slug, '#' ) : false; // Is the parameter already part of the request? If so, modify that parameter. if ( ( $segment = $this->get_parameter_segment( $key, $id, $url ) ) && is_array( $segment ) ) { extract( $segment ); if ( $source == 'querystring' ) { $preg_id = $id ? '\d+' : preg_quote( $id, '#' ); $preg_key = preg_quote( $key, '#' ); $regex = implode( '', [ '#', $id ? "{$preg_id}{$param_sep}" : '', "(({$param_prefix}{$param_sep})?)?{$preg_key}({$param_sep}|=)[^\/&]+&?#i", ] ); $qs = preg_replace( $regex, '', $this->get_router()->get_querystring() ); $this->get_router()->set_querystring( $qs ); $retval = $this->get_routed_url(); } elseif ( $source == 'request_uri' ) { $uri = $this->get_app_request_uri(); $uri = $this->join_paths( explode( $segment, $uri ) ); if ( $settings->router_param_slug && preg_match( "#{$param_slug}/?$#i", $uri, $match ) ) { $retval = $this->remove_url_segment( $match[0], $retval ); } $this->set_app_request_uri( $uri ); $retval = $this->get_routed_url(); } else { $retval = $this->join_paths( explode( $segment, $url ) ); if ( $settings->router_param_slug && preg_match( "#/{$param_slug}$#i", $retval, $match ) ) { $retval = $this->remove_url_segment( $match[0], $retval ); } } } if ( is_string( $retval ) ) { $retval = rtrim( $retval, ' ?&' ); } $retval = ( is_null( $retval ) or is_numeric( $retval ) or is_array( $retval ) ) ? $retval : Router::esc_url( $retval ); $retval = $this->add_post_permalink_to_url( $retval ); $retval = $this->_set_tag_cloud_parameters( $retval, $key, $id ); if ( preg_match( "#(/{$param_slug}/.*)album--#", $retval, $matches ) ) { $retval = str_replace( $matches[0], $matches[1], $retval ); } if ( preg_match( "#(/{$param_slug}/.*)gallery--#", $retval, $matches ) ) { $retval = str_replace( $matches[0], $matches[1], $retval ); } $retval = $this->_set_ngglegacy_page_parameter( $retval, $key ); // For some reason, we're not removing our parameters the way we should. Our routing system seems to be // a bit broken and so I'm adding an exception here. // TODO: Our parameter manipulations need to be flawless. Look into route cause. if ( $key === 'show' ) { $regex = '#/' . $param_slug . '.*(/?(slideshow|thumbnails|imagebrowser)/?)#'; if ( preg_match( $regex, $retval, $matches ) ) { $retval = str_replace( $matches[1], '', $retval ); } } return $retval; } public function _set_tag_cloud_parameters( $retval, $key, $id = null ) { // Get the settings manager. $settings = Settings::get_instance(); // Create the regex pattern. $sep = preg_quote( $settings->get( 'router_param_separator', '--' ), '#' ); if ( $id ) { $id = preg_quote( $id, '#' ) . $sep; } $prefix = preg_quote( $settings->get( 'router_param_prefix', '' ), '#' ); $regex = implode( '', [ '#//?', $id ? "({$id})?" : "(\w+{$sep})?", "($prefix)?gallerytag{$sep}([\w\-_]+)/?#", ] ); // Replace any page parameters with the ngglegacy equivalent. if ( preg_match( $regex, $retval, $matches ) ) { $retval = rtrim( str_replace( $matches[0], "/tags/{$matches[3]}/", $retval ), '/' ); } return $retval; } public function _set_ngglegacy_page_parameter( $retval, $key, $value = null, $id = null, $use_prefix = null ) { // Get the settings manager. $settings = Settings::get_instance(); // Create regex pattern. $param_slug = preg_quote( $settings->get( 'router_param_slug', 'nggallery' ), '#' ); if ( $key == 'nggpage' ) { $regex = "#(/{$param_slug}/.*)(/?page/\\d+/?)(.*)#"; if ( preg_match( $regex, $retval, $matches ) ) { $new_segment = $value ? "/page/{$value}" : ''; $retval = rtrim( str_replace( $matches[0], rtrim( $matches[1], '/' ) . $new_segment . ltrim( $matches[3], '/' ), $retval ), '/' ); } } // Convert the nggpage parameter to a slug. if ( preg_match( "#(/{$param_slug}/.*)nggpage--(.*)#", $retval, $matches ) ) { $retval = rtrim( str_replace( $matches[0], rtrim( $matches[1], '/' ) . '/page/' . ltrim( $matches[2], '/' ), $retval ), '/' ); } // Convert the show parameter to a slug. if ( preg_match( "#(/{$param_slug}/.*)show--(.*)#", $retval, $matches ) ) { $retval = rtrim( str_replace( $matches[0], rtrim( $matches[1], '/' ) . '/' . $matches[2], $retval ), '/' ); $retval = str_replace( NGG_BASIC_SLIDESHOW, 'slideshow', $retval ); $retval = str_replace( NGG_BASIC_THUMBNAILS, 'thumbnails', $retval ); $retval = str_replace( NGG_BASIC_IMAGEBROWSER, 'imagebrowser', $retval ); } return $retval; } public function _set_search_page_parameter( $retval, $key, $value = null, $id = null, $use_prefix = null ) { $settings = Settings::get_instance(); $param_slug = preg_quote( $settings->router_param_slug, '#' ); // Convert the nggsearch parameter to a slug. if ( preg_match( "#(/{$param_slug}/.*)nggsearch--(.*)#", $retval, $matches ) ) { $retval = rtrim( str_replace( $matches[0], rtrim( $matches[1], '/' ) . '/search/' . ltrim( $matches[2], '/' ), $retval ), '/' ); } if ( preg_match( "#(/{$param_slug}/.*)tagfilter--(.*)#", $retval, $matches ) ) { $retval = rtrim( str_replace( $matches[0], rtrim( $matches[1], '/' ) . '/tagfilter/' . ltrim( $matches[2], '/' ), $retval ), '/' ); } return $retval; } /** * Sets the value of a particular parameter * * @param string $key * @param mixed $value * @param mixed $id (optional) * @param bool $use_prefix (optional) * @param bool|string $url (optional) * @return string */ public function set_parameter_value( $key, $value, $id = null, $use_prefix = false, $url = false ) { // Get the settings manager. $settings = $this->_settings; $param_slug = $settings->router_param_slug; // it's difficult to make NextGEN's router work with spaces in parameter names without just encoding them // directly first; replace nggsearch's parameter's spaces with %20. $url = preg_replace_callback( "#(/{$param_slug}/.*)nggsearch--(.*)#", function ( $matches ) { return str_replace( ' ', '%20', $matches[0] ); }, $url ); // Remove the parameter from both the querystring and request uri. $retval = $this->remove_parameter( $key, $id, $url ); // We're modifying a url passed in. if ( $url ) { $parts = parse_url( $retval ); if ( ! isset( $parts['path'] ) ) { $parts['path'] = ''; } $parts['path'] = $this->join_paths( $parts['path'], $param_slug && strpos( $parts['path'], $param_slug ) === false ? $param_slug : '', $this->create_parameter_segment( $key, $value, $id, $use_prefix ) ); $parts['path'] = str_replace( '//', '/', $parts['path'] ); $retval = $this->construct_url_from_parts( $parts ); } // We're modifying the current request. else { // This parameter is being appended to the current request uri. $this->add_parameter_to_app_request_uri( $key, $value, $id, $use_prefix ); // Return the new full url. $retval = $this->get_routed_url(); } $retval = ( is_null( $retval ) || is_numeric( $retval ) || is_array( $retval ) ) ? $retval : Router::esc_url( $retval ); $retval = $this->_set_tag_cloud_parameters( $retval, $key, $id ); $retval = $this->_set_ngglegacy_page_parameter( $retval, $key, $value, $id, $use_prefix ); $retval = $this->_set_search_page_parameter( $retval, $key, $value, $id, $use_prefix ); return $retval; } } Installer.php000064400000016436150212456520007226 0ustar00uninstall( $hard ); } if ( $handler && $hard ) { Settings::get_instance()->destroy(); GlobalSettings::get_instance()->destroy(); } return true; } public static function can_do_upgrade() { $proceed = false; // Proceed if no other process has started the installer routines. if ( ! ( $doing_upgrade = \get_option( 'ngg_doing_upgrade', false ) ) ) { \update_option( 'ngg_doing_upgrade', \time() ); $proceed = true; } // Or, force proceeding if we have a stale ngg_doing_upgrade record. elseif ( $doing_upgrade === true or \time() - $doing_upgrade > 120 ) { \update_option( 'ngg_doing_upgrade', \time() ); $proceed = true; } return $proceed; } public static function done_upgrade() { \delete_option( 'ngg_doing_upgrade' ); } public static function update( $reset = false ) { $local_settings = Settings::get_instance(); $global_settings = GlobalSettings::get_instance(); $do_upgrade = false; // TODO: remove this when POPE v1 compatibility is reached in Pro. if ( \C_NextGEN_Bootstrap::get_pro_api_version() < 4.0 ) { // Get last module list and current module list. Compare... $last_module_list = self::_get_last_module_list( $reset ); $current_module_list = self::_generate_module_info(); $diff = \array_diff( $current_module_list, $last_module_list ); $do_upgrade = ( \count( $diff ) > 0 || \count( $last_module_list ) != \count( $current_module_list ) ); } $ngg_version_setting = $local_settings->get( 'ngg_plugin_version', 0 ); if ( ! $ngg_version_setting || $ngg_version_setting !== NGG_PLUGIN_VERSION ) { $do_upgrade = true; } // Allow NextGEN extensions to trigger this process. $do_upgrade = \apply_filters( 'ngg_do_install_or_setup_process', $do_upgrade ); $can_upgrade = $do_upgrade && self::can_do_upgrade(); if ( $can_upgrade && $do_upgrade ) { // Clear APC cache. if ( \function_exists( 'apc_clear_cache' ) ) { @\apc_clear_cache( 'opcode' ); \apc_clear_cache(); } // Attempt to reset the opcache. NextGEN 3.50+ and Pro 3.30+ moved, renamed, and deleted several files // and purging the opcache should help prevent fatal errors due to cached instructions. if ( \function_exists( 'opcache_reset' ) ) { \opcache_reset(); } // Clear all of our transients. \wp_cache_flush(); Transient::flush(); // Remove all NGG created cron jobs. self::refresh_cron(); // Other Pope applications might be loaded, and therefore all singletons should be destroyed, so that they // can be adapted as necessary. For now, we'll just assume that the factory is the only singleton that will // be used by other Pope applications. if ( class_exists( '\C_Component_Factory' ) ) { \C_Component_Factory::$_instances = []; } foreach ( self::get_all_handlers() as $handler_name => $handler_class ) { $handler = new $handler_class(); if ( \method_exists( $handler, 'install' ) ) { $handler->install( $reset ); } } // Record the current version; changes to this and setting are how updates are triggered. $local_settings->set( 'ngg_plugin_version', NGG_PLUGIN_VERSION ); $global_settings->save(); $local_settings->save(); self::set_role_caps(); \do_action( 'ngg_did_install_or_setup_process' ); } // Update the module list, and remove the update flag. if ( $can_upgrade ) { if ( isset( $current_module_list ) ) { \update_option( 'pope_module_list', $current_module_list ); } self::done_upgrade(); } } public static function _get_last_module_list( $reset = false ) { if ( $reset ) { return []; } // First try getting the list from a single WP option, "pope_module_list". $retval = \get_option( 'pope_module_list', [] ); if ( ! $retval ) { $local_settings = Settings::get_instance(); $retval = $local_settings->get( 'pope_module_list', [] ); $local_settings->delete( 'pope_module_list' ); } return $retval; } protected static function _generate_module_info() { $retval = []; $registry = \C_Component_Registry::get_instance(); $products = [ 'photocrati-nextgen' ]; foreach ( $registry->get_product_list() as $product_id ) { if ( $product_id != 'photocrati-nextgen' ) { $products[] = $product_id; } } foreach ( $products as $product_id ) { foreach ( $registry->get_module_list( $product_id ) as $module_id ) { if ( ( $module = $registry->get_module( $module_id ) ) ) { $module_version = $module->module_version; $module_string = "{$module_id}|{$module_version}"; if ( ! \in_array( $module_string, $retval ) ) { $retval[] = $module_string; } } } } return $retval; } public static function refresh_cron() { if ( ! \extension_loaded( 'suhosin' ) ) { @\ini_set( 'memory_limit', -1 ); } // Remove all cron jobs created by NextGEN Gallery. $cron = \_get_cron_array(); if ( \is_array( $cron ) ) { foreach ( $cron as $timestamp => $job ) { if ( \is_array( $job ) ) { unset( $cron[ $timestamp ]['ngg_delete_expired_transients'] ); if ( empty( $cron[ $timestamp ] ) ) { unset( $cron[ $timestamp ] ); } } } } \_set_cron_array( $cron ); } public static function set_role_caps() { // Set the capabilities for the administrator. $role = \get_role( 'administrator' ); if ( ! $role ) { if ( ! class_exists( 'WP_Roles' ) ) { include_once ABSPATH . '/wp-includes/class-wp-roles.php'; } $roles = new \WP_Roles(); $roles->init_roles(); } // We need this role, no other chance. $role = \get_role( 'administrator' ); if ( ! $role ) { \update_option( 'ngg_init_check', __( 'Sorry, NextGEN Gallery works only with a role called administrator', 'nggallery' ) ); return; } delete_option( 'ngg_init_check' ); $capabilities = [ 'NextGEN Attach Interface', 'NextGEN Change options', 'NextGEN Change style', 'NextGEN Edit album', 'NextGEN Gallery overview', 'NextGEN Manage gallery', 'NextGEN Manage others gallery', 'NextGEN Manage tags', 'NextGEN Upload images', 'NextGEN Use TinyMCE', ]; foreach ( $capabilities as $capability ) { $role->add_cap( $capability ); } } } Router.php000064400000044725150212456520006553 0ustar00context = '/'; } $this->_request_method = ! empty( $_SERVER['REQUEST_METHOD'] ) ? $_SERVER['REQUEST_METHOD'] : null; self::$_lookups = Transient::fetch( $this->_get_cache_key(), [] ); // TODO: only register this once. register_shutdown_function( [ $this, 'cache_lookups' ] ); } /** * @param string|false $context (optional) * @return Router */ public static function get_instance( $context = false ) { if ( ! isset( self::$_instances[ $context ] ) ) { self::$_instances[ $context ] = new Router( $context ); } return self::$_instances[ $context ]; } public function register_hooks() { \add_action( 'template_redirect', [ $this, 'restore_request_uri' ], 1 ); // These two things cause conflicts in NGG. So we temporarily disable them and then reactivate them, if they // were used, in the restore_request_uri() method. if ( \has_action( 'template_redirect', 'wp_old_slug_redirect' ) ) { \remove_action( 'template_redirect', 'wp_old_slug_redirect' ); } if ( \has_action( 'template_redirect', 'redirect_canonical' ) ) { \remove_action( 'template_redirect', 'redirect_canonical' ); } \add_action( 'the_post', [ $this, 'fix_page_parameter' ] ); } /** * When WordPress sees a url like http://foobar.com/nggallery/page/2/, it thinks that it is an * invalid url. Therefore, we modify the request uri before WordPress parses the request, and then * restore the request uri afterwards */ public function restore_request_uri() { if ( isset( $_SERVER['NGG_ORIG_REQUEST_URI'] ) ) { $request_uri = $_SERVER['NGG_ORIG_REQUEST_URI']; $_SERVER['UNENCODED_URL'] = $_SERVER['HTTP_X_ORIGINAL_URL'] = $_SERVER['REQUEST_URI'] = $request_uri; if ( isset( $_SERVER['ORIG_PATH_INFO'] ) ) { $_SERVER['PATH_INFO'] = $_SERVER['ORIG_PATH_INFO']; } } else { // This is the proper behavior, but it causes problems with WPML. if ( self::$use_old_slugs ) { \wp_old_slug_redirect(); } if ( self::$use_canonical_redirect ) { \redirect_canonical(); } } } public function join_paths() { $args = func_get_args(); $parts = $this->_flatten_array( $args ); foreach ( $parts as &$part ) { $part = trim( str_replace( '\\', '/', $part ), '/' ); } return implode( '/', $parts ); } /** * Removes a segment from a url * * @param string $segment * @param string $url * @return string */ public function remove_url_segment( $segment, $url ) { $retval = $url; $parts = parse_url( $url ); // If the url has a path, then we can remove a segment. if ( isset( $parts['path'] ) && $segment != '/' ) { if ( substr( $segment, -1 ) == '/' ) { $segment = substr( $segment, -1 ); } $segment = preg_quote( $segment, '#' ); if ( preg_match( "#{$segment}#", $parts['path'], $matches ) ) { $parts['path'] = str_replace( '//', '/', str_replace( $matches[0], '', $parts['path'] ) ); $retval = $this->construct_url_from_parts( $parts ); } } return $retval; } /** * Flattens an array of arrays to a single array * * @param array $array * @param array $parent (optional) * @param bool $exclude_duplicates (optional - defaults to TRUE) * @return array */ public function _flatten_array( $array, $parent = null, $exclude_duplicates = true ) { if ( is_array( $array ) ) { // We're to add each element to the parent array. if ( $parent ) { foreach ( $array as $index => $element ) { foreach ( $this->_flatten_array( $array ) as $sub_element ) { if ( $exclude_duplicates ) { if ( ! in_array( $sub_element, $parent ) ) { $parent[] = $sub_element; } } else { $parent[] = $sub_element; } } } $array = $parent; } else { // We're starting the process.. $index = 0; while ( isset( $array[ $index ] ) ) { $element = $array[ $index ]; if ( is_array( $element ) ) { $array = $this->_flatten_array( $element, $array ); unset( $array[ $index ] ); } $index += 1; } $array = array_values( $array ); } } else { $array = [ $array ]; } return $array; } public function join_querystrings() { $retval = []; $params = func_get_args(); $parts = $this->_flatten_array( $params ); foreach ( $parts as $part ) { $part = explode( '&', $part ); foreach ( $part as $segment ) { $segment = explode( '=', $segment ); $key = $segment[0]; $value = isset( $segment[1] ) ? $segment[1] : ''; $retval[ $key ] = $value; } } return $this->assoc_array_to_querystring( $retval ); } public function assoc_array_to_querystring( $arr ) { $retval = []; foreach ( $arr as $key => $val ) { if ( strlen( $key ) ) { $retval[] = strlen( $val ) ? "{$key}={$val}" : $key; } } return implode( '&', $retval ); } /** * Constructs an url from individual parts, created by parse_url * * @param array $parts * @return string */ public function construct_url_from_parts( $parts ) { // let relative paths be relative, and full paths full. $prefix = ''; if ( ! empty( $parts['scheme'] ) && ! empty( $parts['host'] ) ) { $prefix = $parts['scheme'] . '://' . $parts['host']; if ( ! empty( $parts['port'] ) ) { $prefix .= ':' . $parts['port']; } } $retval = $this->join_paths( $prefix, isset( $parts['path'] ) ? str_replace( '//', '/', trailingslashit( $parts['path'] ) ) : '' ); if ( isset( $parts['query'] ) && $parts['query'] ) { $retval .= untrailingslashit( "?{$parts['query']}" ); } return $retval; } /** * Returns the request uri with the parameter segments stripped * * @param string $request_uri * @return string */ public function strip_param_segments( $request_uri, $remove_slug = true ) { $retval = $request_uri ? $request_uri : '/'; $settings = Settings::get_instance(); $sep = preg_quote( $settings->get( 'router_param_separator', '--' ), '#' ); $param_regex = "#((?P\w+){$sep})?(?\w+){$sep}(?P.+)/?$#"; $slug = $settings->get( 'router_param_slug', 'nggallery' ) && $remove_slug ? '/' . preg_quote( $settings->get( 'router_param_slug', 'nggallery' ), '#' ) : ''; $slug_regex = '#' . $slug . '/?$#'; // Remove all parameters. while ( @preg_match( $param_regex, $retval, $matches ) ) { $match_regex = '#' . preg_quote( array_shift( $matches ), '#' ) . '$#'; $retval = preg_replace( $match_regex, '', $retval ); } // Remove the slug or trailing slash. if ( @preg_match( $slug_regex, $retval, $matches ) ) { $match_regex = '#' . preg_quote( array_shift( $matches ), '#' ) . '$#'; $retval = preg_replace( $match_regex, '', $retval ); } // If there's a slug, we can assume everything after is a parameter, // even if it's not in our desired format. $retval = preg_replace( '#' . $slug . '.*$#', '', $retval ); if ( ! $retval ) { $retval = '/'; } return $retval; } public function set_routed_app( $app ) { $this->_routed_app = $app; } /** * @return RoutingApp */ public function get_routed_app() { return $this->_routed_app ? $this->_routed_app : $this->get_default_app(); } /** * @return RoutingApp */ public function get_default_app() { if ( is_null( $this->_default_app ) ) { $this->_default_app = $this->create_app(); } return $this->_default_app; } public function route( $patterns, $handler = false ) { $this->get_default_app()->route( $patterns, $handler ); } public function rewrite( $src, $dst, $redirect = false ) { $this->get_default_app()->rewrite( $src, $dst, $redirect ); } public function get_parameter( $key, $prefix = null, $default = null ) { return $this->get_routed_app()->get_parameter( $key, $prefix, $default ); } public function param( $key, $prefix = null, $default = null ) { return $this->get_parameter( $key, $prefix, $default ); } public function has_parameter_segments() { return $this->get_routed_app()->has_parameter_segments(); } public function passthru() { $this->get_default_app()->passthru(); } public function get_url( $uri = '/', $with_qs = true, $site_url = false ) { static $cache = []; $key = implode( '|', [ $uri, $with_qs, $site_url ] ); if ( isset( $cache[ $key ] ) ) { return $cache[ $key ]; } else { $retval = $this->join_paths( $this->get_base_url( $site_url ), $uri ); if ( $with_qs ) { $parts = parse_url( $retval ); if ( ! isset( $parts['query'] ) ) { $parts['query'] = $this->get_querystring(); } else { $parts['query'] = $this->join_querystrings( $parts['query'], $this->get_querystring() ); } $retval = $this->construct_url_from_parts( $parts ); } $retval = str_replace( '\\', '/', $retval ); // Determine whether the url is a directory or file on the filesystem // If so, then we do NOT need /index.php as part of the url. $base_url = $this->get_base_url(); $filename = str_replace( $base_url, \Imagely\NGG\Util\Filesystem::get_instance()->get_document_root(), $retval ); if ( $retval && $retval != $base_url && @file_exists( $filename ) ) { // Remove index.php from the url. $retval = $this->remove_url_segment( '/index.php', $retval ); // Static urls don't end with a slash. $retval = untrailingslashit( $retval ); } $cache[ $key ] = $retval; return $retval; } } /** * Returns a static url * * @param string $path * @param string|false $module (optional) * @return string */ public function get_static_url( $path, $module = false ) { return \Imagely\NGG\Display\StaticPopeAssets::get_url( $path, $module ); } /** * Gets the routed url * * @return string */ public function get_routed_url() { $retval = $this->get_url( $this->get_request_uri() ); if ( ( $app = $this->get_routed_app() ) ) { $retval = $this->get_url( $app->get_app_uri() ); } return $retval; } /** * Gets the base url for the router * * @param bool $type * @return string */ public function get_base_url( $type = false ) { if ( $this->has_cached_base_url( $type ) ) { return $this->get_cached_base_url( $type ); } return $this->get_computed_base_url( $type ); } /** * Determines if the current request is over HTTPs or not */ public function is_https() { return ( ( ! empty( $_SERVER['HTTPS'] ) && strtolower( $_SERVER['HTTPS'] ) !== 'off' ) || ( ! empty( $_SERVER['HTTP_USESSL'] ) && strtolower( $_SERVER['HTTP_USESSL'] ) !== 'off' ) || ( ! empty( $_SERVER['REDIRECT_HTTPS'] ) && strtolower( $_SERVER['REDIRECT_HTTPS'] ) !== 'off' ) || ( ! empty( $_SERVER['SERVER_PORT'] ) && $_SERVER['SERVER_PORT'] == 443 ) ); } /** * Serve request using defined Routing Apps */ public function serve_request() { $served = false; // iterate over all apps, and serve the route. /** @var \Imagely\NGG\Util\RoutingApp $app */ foreach ( $this->get_apps() as $app ) { if ( ( $served = $app->serve_request( $this->context ) ) ) { break; } } return $served; } /** * Gets the querystring of the current request * * @return null|bool */ public function get_querystring() { return isset( $_SERVER['QUERY_STRING'] ) ? $_SERVER['QUERY_STRING'] : null; } public function set_querystring( $value ) { $_SERVER['QUERY_STRING'] = $value; } /** * Gets the request for the router * * @param bool $with_params (optional) Default = true * @return string */ public function get_request_uri( $with_params = true ) { if ( ! empty( $_SERVER['NGG_ORIG_REQUEST_URI'] ) ) { $retval = $_SERVER['NGG_ORIG_REQUEST_URI']; } elseif ( ! empty( $_SERVER['PATH_INFO'] ) ) { $retval = $_SERVER['PATH_INFO']; } else { $retval = $_SERVER['REQUEST_URI']; } // Remove the querystring. if ( ( $index = strpos( $retval, '?' ) ) !== false ) { $retval = substr( $retval, 0, $index ); } // Remove the router's context. $retval = preg_replace( '#^' . preg_quote( $this->context, '#' ) . '#', '', $retval ); // Remove the params. if ( ! $with_params ) { $retval = $this->strip_param_segments( $retval ); } // Ensure that request uri starts with a slash. if ( strpos( $retval, '/' ) !== 0 ) { $retval = "/{$retval}"; } return $retval; } /** * Gets the method of the HTTP request * * @return string */ public function get_request_method() { return $this->_request_method; } /** * @param string $name * @return RoutingApp */ public function create_app( $name = '/' ) { $app = new RoutingApp( $name ); $this->_apps[] = $app; return $app; } /** * Gets a list of apps registered for the router * * @return array */ public function get_apps() { usort( $this->_apps, [ &$this, '_sort_apps' ] ); return array_reverse( $this->_apps ); } /** * Sorts apps.This is needed because we want the most specific app to be executed first * * @return int */ public function _sort_apps( RoutingApp $a, RoutingApp $b ) { return strnatcmp( $a->context, $b->context ); } public function _get_cache_key() { return Transient::create_key( 'WordPress-Router', 'get_base_url' ); } public function cache_lookups() { Transient::update( $this->_get_cache_key(), self::$_lookups ); } public function has_cached_base_url( $type = false ) { return isset( self::$_lookups[ $type ] ); } public function get_cached_base_url( $type = false ) { return self::$_lookups[ $type ]; } public function get_computed_base_url( $site_url = false ) { $retval = null; $add_index_dot_php = true; if ( in_array( $site_url, [ true, 'site' ], true ) ) { $retval = site_url(); } elseif ( in_array( $site_url, [ false, 'home' ], true ) ) { $retval = home_url(); } elseif ( in_array( $site_url, [ 'plugins', 'plugin' ], true ) ) { $retval = plugins_url(); $add_index_dot_php = false; } elseif ( in_array( $site_url, [ 'plugins_mu', 'plugin_mu' ], true ) ) { $retval = WPMU_PLUGIN_URL; $retval = set_url_scheme( $retval ); $retval = apply_filters( 'plugins_url', $retval, '', '' ); $add_index_dot_php = false; } elseif ( in_array( $site_url, [ 'templates', 'template', 'themes', 'theme' ], true ) ) { $retval = get_template_directory_uri(); $add_index_dot_php = false; } elseif ( in_array( $site_url, [ 'styles', 'style', 'stylesheets', 'stylesheet' ], true ) ) { $retval = get_stylesheet_directory_uri(); $add_index_dot_php = false; } elseif ( in_array( $site_url, [ 'content' ], true ) ) { $retval = content_url(); $add_index_dot_php = false; } elseif ( in_array( $site_url, [ 'root' ], true ) ) { $retval = get_option( 'home' ); if ( is_ssl() ) { $scheme = 'https'; } else { $scheme = parse_url( $retval, PHP_URL_SCHEME ); } $retval = set_url_scheme( $retval, $scheme ); } elseif ( in_array( $site_url, [ 'gallery', 'galleries' ], true ) ) { $root_type = NGG_GALLERY_ROOT_TYPE; $add_index_dot_php = false; if ( $root_type === 'content' ) { $retval = content_url(); } else { $retval = site_url(); } } else { $retval = site_url(); } if ( $add_index_dot_php ) { $retval = $this->_add_index_dot_php_to_url( $retval ); } if ( $this->is_https() ) { $retval = preg_replace( '/^http:\\/\\//i', 'https://', $retval, 1 ); } return $retval; } public function _add_index_dot_php_to_url( $url ) { if ( strpos( $url, '/index.php' ) === false ) { $pattern = get_option( 'permalink_structure' ); if ( ! $pattern or strpos( $pattern, '/index.php' ) !== false ) { $url = $this->join_paths( $url, '/index.php' ); } } return $url; } /** * This code was originally added to correct a bug in Pro 1.0.10 and was meant to be temporary. However now the * albums' pagination relies on this to function correctly, and fixing it properly would require more time than * it is worth. */ public function fix_page_parameter() { global $post; if ( $post && is_object( $post ) && is_string( $post->post_content ) && ( strpos( $post->post_content, '' ) === false ) && ( strpos( $_SERVER['REQUEST_URI'], '/page/' ) !== false ) && preg_match( '#/page/(\\d+)#', $_SERVER['REQUEST_URI'], $match ) ) { $_REQUEST['page'] = $match[1]; } } /** * Checks and cleans a URL. This function is forked from WordPress. * * A number of characters are removed from the URL. If the URL is for displaying (the default behaviour) ampersands * are also replaced. The 'clean_url' filter is applied to the returned cleaned URL. * * @param string $url The URL to be cleaned. * @param array $protocols Optional. An array of acceptable protocols. * @param string $context Use esc_url_raw() for database usage. * @return string The cleaned $url after the 'clean_url' filter is applied. */ public static function esc_url( $url, $protocols = null, $context = 'display' ) { $original_url = $url; if ( '' == $url ) { return $url; } $url = preg_replace( '|[^a-z0-9 \\-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url ); $strip = [ '%0d', '%0a', '%0D', '%0A' ]; $url = \_deep_replace( $strip, $url ); $url = str_replace( ';//', '://', $url ); // If the URL doesn't appear to contain a scheme, we presume it needs https:// prepended (unless a relative // link starting with /, # or ? or a php file). if ( strpos( $url, ':' ) === false && ! in_array( $url[0], [ '/', '#', '?' ] ) && ! preg_match( '/^[a-z0-9-]+?\.php/i', $url ) ) { $url = \is_ssl() ? 'https://' : 'http://' . $url; } // Replace ampersands and single quotes only when displaying. if ( 'display' == $context ) { $url = \wp_kses_normalize_entities( $url ); $url = str_replace( '&', '&', $url ); $url = str_replace( "'", ''', $url ); $url = str_replace( ' ', '%20', $url ); } if ( '/' === $url[0] ) { $good_protocol_url = $url; } else { if ( ! is_array( $protocols ) ) { $protocols = \wp_allowed_protocols(); } $good_protocol_url = \wp_kses_bad_protocol( $url, $protocols ); if ( strtolower( $good_protocol_url ) != strtolower( $url ) ) { return ''; } } return \apply_filters( 'clean_url', $good_protocol_url, $original_url, $context ); } } UsageTracking.php000064400000014147150212456520010015 0ustar00user_agent = 'NextGen/' . NGG_PLUGIN_VERSION . '; ' . get_bloginfo( 'url' ); $this->endpoint = 'https://evusage.enviragallery.com/v1/nextgen-checkin/'; } /** * Register hooks. * * @since 3.59.5 * * @return void */ public function hooks() { $onboarding_data = get_option( 'ngg_onboarding_data', [] ); $enabled = $onboarding_data['_usage_tracking'] ?? false; $enabled = filter_var( $enabled, FILTER_VALIDATE_BOOLEAN ); // Check the license type. $type = ( new Onboarding_Wizard() )->get_license_type(); if ( ! $enabled || 'lite' !== $type ) { return; // Return early if usage tracking is disabled or the license type is not lite. } add_action( 'admin_init', [ $this, 'schedule_send' ] ); add_filter( 'cron_schedules', [ $this, 'add_schedules' ], 99 ); add_action( 'nextgen_usage_tracking_cron', [ $this, 'send_checkin' ] ); } /** * Get the settings to send. * * @since 3.59.5 * @return array */ protected function get_settings() { $settings = get_option( 'ngg_options', [] ); $settings_to_send = []; foreach ( $settings as $key => $value ) { if ( empty( $value ) || ( false !== strpos( $key, 'stripe' ) ) ) { continue; } $settings_to_send[ $key ] = $value; } return $settings_to_send; } /** * Get the data to send * * @since 3.59.5 * * @return array */ private function get_data() { $data = []; // Retrieve current theme info. $theme_data = wp_get_theme(); $sites_count = 1; if ( is_multisite() ) { if ( function_exists( 'get_blog_count' ) ) { $sites_count = get_blog_count(); } else { $sites_count = 'Not Set'; } } $settings = $this->get_settings(); $data['nextgen_version'] = NGG_PLUGIN_VERSION; $data['ng_type'] = 'lite'; $data['php_version'] = phpversion(); $data['wp_version'] = get_bloginfo( 'version' ); $data['server'] = $_SERVER['SERVER_SOFTWARE'] ?? 'CLI'; // phpcs:ignore $data['over_time'] = get_option( 'nextgen_over_time', [] ); $data['multisite'] = is_multisite(); $data['url'] = home_url(); $data['themename'] = $theme_data->get( 'Name' ); $data['themeversion'] = $theme_data->get( 'Version' ); $data['email'] = get_bloginfo( 'admin_email' ); $data['settings'] = $settings; $data['pro'] = false; $data['sites'] = $sites_count; $data['usagetracking'] = false; $data['usercount'] = function_exists( 'get_user_count' ) ? get_user_count() : 'Not Set'; $data['timezoneoffset'] = wp_date( 'P' ); // Not used on sol. $data['tracking_mode'] = ''; $data['events_mode'] = ''; $data['usesauth'] = ''; $data['autoupdate'] = false; // Retrieve current plugin information. if ( ! function_exists( 'get_plugins' ) ) { include_once ABSPATH . '/wp-admin/includes/plugin.php'; } $plugins = array_keys( get_plugins() ); $active_plugins = get_option( 'active_plugins', [] ); foreach ( $plugins as $key => $plugin ) { if ( in_array( $plugin, $active_plugins, true ) ) { // Remove active plugins from list so we can show active and inactive separately. unset( $plugins[ $key ] ); } } $data['active_plugins'] = $active_plugins; $data['inactive_plugins'] = $plugins; $data['locale'] = get_locale(); return $data; } /** * Send the checkin * * @since 3.59.5 * * @return bool */ public function send_checkin( $ignore_last_checkin = false ) { $ignore_last_checkin = $ignore_last_checkin || defined( DOING_CRON ) && DOING_CRON; $home_url = trailingslashit( home_url() ); if ( strpos( $home_url, 'imagely.com' ) !== false ) { return false; } // Send a maximum of once per week. $last_send = get_option( 'nextgen_usage_tracking_last_checkin' ); if ( is_numeric( $last_send ) && $last_send > strtotime( '-1 week' ) && ! $ignore_last_checkin ) { return false; } $request = wp_remote_post( $this->endpoint, [ 'method' => 'POST', 'timeout' => 5, 'redirection' => 5, 'httpversion' => '1.1', 'blocking' => false, 'body' => $this->get_data(), 'user-agent' => $this->user_agent, ] ); // If we have completed successfully, recheck in 1 week. update_option( 'nextgen_usage_tracking_last_checkin', time() ); return true; } /** * Schedule the checkin * * @since 3.59.5 * @return void */ public function schedule_send() { if ( wp_next_scheduled( 'nextgen_usage_tracking_cron' ) ) { return; } $tracking = []; $tracking['day'] = wp_rand( 0, 6 ); $tracking['hour'] = wp_rand( 0, 23 ); $tracking['minute'] = wp_rand( 0, 59 ); $tracking['second'] = wp_rand( 0, 59 ); $tracking['offset'] = ( $tracking['day'] * DAY_IN_SECONDS ); $tracking['offset'] += ( $tracking['hour'] * HOUR_IN_SECONDS ); $tracking['offset'] += ( $tracking['minute'] * MINUTE_IN_SECONDS ); $tracking['offset'] += $tracking['second']; $tracking['initsend'] = strtotime( 'next sunday' ) + $tracking['offset']; wp_schedule_event( $tracking['initsend'], 'weekly', 'nextgen_usage_tracking_cron' ); update_option( 'nextgen_usage_tracking_config', wp_json_encode( $tracking ) ); } /** * Add weekly schedule * * @since 3.59.5 * * @param array $schedules Array of schedules. * * @return array */ public function add_schedules( $schedules = [] ) { if ( isset( $schedules['weekly'] ) ) { return $schedules; } $schedules['weekly'] = [ 'interval' => 604800, 'display' => __( 'Once Weekly', 'nextgen-gallery' ), ]; return $schedules; } } Sanitization.php000064400000001223150212456520007731 0ustar00 $data ) { $value->{$key} = self::recursive_stripslashes( $data ); } } return $value; } }