public function fetchFeed($vURLs, $numItems = 0, $fCacheRenew = false)
 {
     $arrURLs = is_array($vURLs) ? $vURLs : (array) $vURLs;
     $strURLID = md5(serialize($arrURLs));
     if (!isset($this->arrFeedItems[$strURLID]) && $fCacheRenew == false) {
         $this->arrFeedItems[$strURLID] = (array) AmazonAutoLinks_WPUtilities::getTransient($this->strTransientPrefix . $strURLID);
         unset($this->arrFeedItems[$strURLID][0]);
         // casting array causes the 0 key,
     }
     // If it's out of stock, fill the array by fetching the feed.
     if (empty($this->arrFeedItems[$strURLID])) {
         // When an array of urls is passed to the Simple Pie's set_feed_url() method, the memory usage increases largely.
         // So fetch the feeds one by one per url and store the output into an array.
         foreach ($arrURLs as $strURL) {
             $oFeed = $this->getFeedObj($strURL, null, $fCacheRenew ? 0 : 3600);
             // foreach ( $oFeed->get_items( 0, $numItems * 3 ) as $item ) does not change the memory usage
             foreach ($oFeed->get_items() as $oItem) {
                 $this->arrFeedItems[$strURLID][$oItem->get_title()] = array('strContent' => $oItem->get_content(), 'strDescription' => $oItem->get_description(), 'strTitle' => $oItem->get_title(), 'strDate' => $oItem->get_title(), 'strAuthor' => $oItem->get_date('j F Y, g:i a'), 'strLink' => $oItem->get_permalink());
             }
             // For PHP below 5.3 to release the memory.
             $oFeed->__destruct();
             // Do what PHP should be doing on it's own.
             unset($oFeed);
         }
         // This life span should be little longer than the feed cache life span, which is 1700.
         AmazonAutoLinks_WPUtilities::setTransient($this->strTransientPrefix . $strURLID, $this->arrFeedItems[$strURLID], 1800);
         // 30 minutes
     }
     $arrOut = $this->arrFeedItems[$strURLID];
     if ($numItems) {
         array_splice($arrOut, ${$numItems});
     }
     return $arrOut;
 }
 public function validation_aal_add_category_unit_set_category_unit_options($aInput, $aOldInput)
 {
     // validation + _ + page slug + tab slug
     $_fVerified = true;
     $_aErrors = array();
     // Check the limitation.
     if ($this->oOption->isUnitLimitReached()) {
         $this->setFieldErrors(array('error'));
         // must set an field error array which does not yield empty so that it won't be redirected.
         $this->setSettingNotice(sprintf(__('Please upgrade to <A href="%1$s">Pro</a> to add more units! Make sure to empty the <a href="%2$s">trash box</a> to delete the units completely!', 'amazon-auto-links'), 'http://en.michaeluno.jp/amazon-auto-links-pro/', admin_url('edit.php?post_status=trash&post_type=' . AmazonAutoLinks_Commons::PostTypeSlug)));
         return $aOldInput;
     }
     if (empty($aInput['aal_add_category_unit']['category']['category_associate_id'])) {
         $_aErrors['category']['category_associate_id'] = __('The associate ID cannot be empty.', 'amazon-auto-links');
         $_fVerified = false;
     }
     // An invalid value is found.
     if (!$_fVerified) {
         // Set the error array for the input fields.
         $this->setFieldErrors($_aErrors);
         $this->setSettingNotice(__('There was an error in your input.', 'amazon-auto-links'));
         return $aOldInput;
     }
     // Drop the sections.
     $arrNewFields = array();
     foreach ($aInput['aal_add_category_unit'] as $strSection => $arrFields) {
         $arrNewFields = $arrNewFields + $arrFields;
     }
     $arrSanitizedFields = array();
     // Remove the category_ prefix in the keys.
     foreach ($arrNewFields as $strKey => $vValue) {
         $arrSanitizedFields[preg_replace('/^category_/', '', $strKey)] = $vValue;
     }
     $arrSanitizedFields['categories'] = array();
     $arrSanitizedFields['categories_exclude'] = array();
     $arrSanitizedFields = $this->oOption->sanitizeUnitOpitons($arrSanitizedFields);
     // If nothing is checked for the feed type, enable the bestseller item.
     if (!array_filter($arrSanitizedFields['feed_type'])) {
         $arrSanitizedFields['feed_type']['bestsellers'] = true;
     }
     $arrTempUnitOptions = (array) AmazonAutoLinks_WPUtilities::getTransient('AAL_CreateUnit_' . $arrSanitizedFields['transient_id']);
     AmazonAutoLinks_WPUtilities::setTransient('AAL_CreateUnit_' . $arrSanitizedFields['transient_id'], AmazonAutoLinks_Utilities::uniteArrays($arrSanitizedFields, $arrTempUnitOptions), 60 * 10 * 6 * 24);
     // AmazonAutoLinks_Debug::logArray( $arrSanitizedFields );
     return $aInput;
 }
 /**
  * The global page load
  * 
  */
 public function load_AmazonAutoLinks_AdminPage()
 {
     // Check the support rate and ads visibility
     if (!(isset($_GET['tab'], $_GET['bounce_url']) && $_GET['tab'] == 'support') && !$this->oOption->arrOptions['aal_settings']['support']['agreed'] && $this->oOption->isSupportMissing()) {
         $strBounceURL = htmlspecialchars_decode(AmazonAutoLinks_WPUtilities::getCurrentAdminURL());
         $strBounceURL = str_replace('tab=support', '', $strBounceURL);
         // prevent infinite redirects            ;
         $strBounceURL = remove_query_arg('aal-option-upgrade', $strBounceURL);
         AmazonAutoLinks_WPUtilities::setTransient('AAL_BounceURL', $strBounceURL, 60 * 10);
         exit(wp_redirect(admin_url('edit.php?post_type=' . AmazonAutoLinks_Commons::PostTypeSlug . '&page=aal_settings&tab=support&bounce_url=AAL_BounceURL')));
     }
     // Check the v1 options exist and redirect to the v1 options importer.
     if (!(isset($_GET['tab'], $_GET['bounce_url']) && ($_GET['tab'] == 'import_v1_options' || $_GET['tab'] == 'support')) && !$this->oOption->arrOptions['aal_settings']['import_v1_options']['dismiss'] && false !== get_option('amazonautolinks')) {
         $strBounceURL = htmlspecialchars_decode(AmazonAutoLinks_WPUtilities::getCurrentAdminURL());
         $strBounceURL = str_replace('tab=import_v1_options', '', $strBounceURL);
         // prevent infinite redirects
         AmazonAutoLinks_WPUtilities::setTransient('AAL_BounceURL_Importer', $strBounceURL, 60 * 10);
         $this->setAdminNotice(sprintf(__('Please upgrade the options of previous versions of the plugin by clicking <a href="%1$s">here</a>.', 'amazon-auto-links') . ' ' . __('Before you do it, please <strong>back up</strong> the database.', 'amazon-auto-links') . ' ' . __('Dismiss this message by clicking <a href="%2$s">here</a>.', 'amazon-auto-links'), admin_url('edit.php?post_type=' . AmazonAutoLinks_Commons::PostTypeSlug . '&page=aal_settings&tab=import_v1_options&bounce_url=AAL_BounceURL_Importer'), admin_url('edit.php?post_type=' . AmazonAutoLinks_Commons::PostTypeSlug . '&page=aal_settings&tab=import_v1_options&action=dismiss&bounce_url=AAL_BounceURL_Importer')), 'error');
         return;
     }
     // Check v1 option importer messages
     if (isset($_GET['aal-option-upgrade'])) {
         switch ($_GET['aal-option-upgrade']) {
             case 'not-found':
                 $this->setAdminNotice(__('Could not find the options to import.', 'amazon-auto-links'), 'error');
                 break;
             case 'succeed':
                 $this->setAdminNotice(sprintf(__('Options have been imported. ( %1$s unit(s) )', 'amazon-auto-links'), $_GET['count']), 'updated');
                 break;
             case 'partial':
                 $this->setAdminNotice(sprintf(__('Options been partially imported. ( %1$s unit(s) )', 'amazon-auto-links'), $_GET['count']), 'error');
                 break;
             case 'failed':
                 $this->setAdminNotice(__('No unit was imported.', 'amazon-auto-links'), 'error');
                 break;
         }
     }
     // 3+ Add a setting notice to upgrade the options to v3
     $_sBounceURL = htmlspecialchars_decode(AmazonAutoLinks_WPUtilities::getCurrentAdminURL());
     $_sBounceURL = str_replace('tab=create_v3_options', '', $_sBounceURL);
     // prevent infinite redirects
     AmazonAutoLinks_WPUtilities::setTransient('AAL_BounceURL_Importer', $_sBounceURL, 60 * 10);
     $this->setAdminNotice('<strong>' . AmazonAutoLinks_Commons::Name . '</strong>: ' . sprintf(__('Please upgrade the options by clicking <strong><a href="%1$s">here</a></strong>.', 'amazon-auto-links') . ' ' . __('Before you do it, please <strong>back up</strong> the database.', 'amazon-auto-links'), admin_url('edit.php?post_type=' . AmazonAutoLinks_Commons::PostTypeSlug . '&page=aal_settings&tab=create_v3_options&bounce_url=AAL_BounceURL_Importer')), 'error');
 }
 protected function fetchItems($arrURLs, $numItems = 1)
 {
     $strURLID = md5(serialize(is_string($arrURLs) ? array($arrURLs) : $arrURLs));
     if (!isset($this->arrFeedItems[$strURLID])) {
         $this->arrFeedItems[$strURLID] = (array) AmazonAutoLinks_WPUtilities::getTransient($this->strTransientPrefix . $strURLID);
         $this->arrFeedItems[$strURLID] = array_filter($this->arrFeedItems[$strURLID]);
         // casting array causes the 0 key
     }
     // If it's out of stock, fill the array by fetching the feed.
     shuffle($this->arrFeedItems[$strURLID]);
     $this->arrFeedItems[$strURLID] = array_unique($this->arrFeedItems[$strURLID]);
     if (count($this->arrFeedItems[$strURLID]) < $numItems) {
         $oReplace = new AmazonAutoLinks_HTMLElementReplacer(get_bloginfo('charset'));
         // When an array of urls is passed to the Simple Pie's set_feed_url() method, the memory usage increases largely.
         // So fetch the feeds one by one per url and store the output into an array.
         foreach ($arrURLs as $strURL) {
             $oFeed = $this->getFeedObj($strURL, $numItems * 10);
             // multiplied by three to store items more than enough for next calls.
             foreach ($oFeed->get_items() as $item) {
                 // foreach ( $oFeed->get_items( 0, $numItems * 3 ) as $item ) does not change the memory usage
                 $this->arrFeedItems[$strURLID][] = $oReplace->Perform($item->get_content());
             }
             // For PHP below 5.3 to release the memory.
             $oFeed->__destruct();
             // Do what PHP should be doing on it's own.
             unset($oFeed);
         }
         unset($oReplace);
         // This life span should be little longer than the feed cache life span, which is 1700.
         AmazonAutoLinks_WPUtilities::setTransient($this->strTransientPrefix . $strURLID, $this->arrFeedItems[$strURLID], 1800);
         // 30 minutes
     }
     $this->arrFeedItems[$strURLID] = array_unique($this->arrFeedItems[$strURLID]);
     shuffle($this->arrFeedItems[$strURLID]);
     $strOut = '';
     for ($i = 1; $i <= $numItems; $i++) {
         $strOut .= array_pop($this->arrFeedItems[$strURLID]);
     }
     return $strOut;
 }
 public function start_AmazonAutoLinks_PostType_AutoInsert()
 {
     $this->setPostTypeArgs(array('labels' => array('name' => __('Auto Insert', 'amazon-auto-links'), 'singular_name' => __('Auto Insert', 'amazon-auto-links'), 'menu_name' => __('Manage Auto Insert', 'amazon-auto-links'), 'add_new' => __('Add New Auto Insert', 'amazon-auto-links'), 'add_new_item' => __('Add New Auto Insert', 'amazon-auto-links'), 'edit' => __('Edit', 'amazon-auto-links'), 'edit_item' => __('Edit Auto Insert', 'amazon-auto-links'), 'new_item' => __('New Auto Insert', 'amazon-auto-links'), 'view' => __('View', 'amazon-auto-links'), 'view_item' => __('View Auto Insert', 'amazon-auto-links'), 'search_items' => __('Search Auto Insert Definitions', 'amazon-auto-links'), 'not_found' => __('No definitions found for Auto Insert', 'amazon-auto-links'), 'not_found_in_trash' => __('No definitions Found for Auto Insert in Trash', 'amazon-auto-links'), 'parent' => __('Parent Auto Insert', 'amazon-auto-links')), 'public' => false, 'menu_position' => 120, 'supports' => array('title'), 'taxonomies' => array(''), 'menu_icon' => AmazonAutoLinks_Commons::getPluginURL('asset/image/menu_icon_16x16.png'), 'has_archive' => false, 'hierarchical' => false, 'show_admin_column' => true, 'exclude_from_search' => true, 'publicly_queryable' => false, 'show_ui' => false, 'show_in_nav_menus' => false, 'show_in_menu' => false));
     // Check custom actions
     if (is_admin() && $GLOBALS['pagenow'] == 'edit.php' && isset($_GET['post_type']) && $_GET['post_type'] == AmazonAutoLinks_Commons::PostTypeSlugAutoInsert) {
         // add_filter( 'post_row_actions', array( $this, 'modifyRowActions' ), 10, 2 );
         add_filter('bulk_actions-edit-' . $this->oProps->strPostType, array($this, 'modifyBulkActionsDropDownList'));
         // $this->setAutoSave( false );
         $this->setAuthorTableFilter(false);
         $this->strCustomNonce = uniqid();
         AmazonAutoLinks_WPUtilities::setTransient('AAL_Nonce_' . $this->strCustomNonce, $this->strCustomNonce, 60 * 10);
         $this->handleCustomActions();
     }
     // if not in admin or the post type slug is not set, the oLink object won't be set.
     if (isset($this->oLink)) {
         $this->oLink->strSettingPageLinkTitle = __('Auto-Insert', 'amazon-auto-links');
     }
     // If a unit is deleted, check auto-insert items if there are empty items. If so, delete them as well.
     if (is_admin()) {
         add_action('before_delete_post', array($this, '_replyToCheckEmptyAutoInsert'));
     }
 }
 /**
  * A wrapper method for the set_transient() function.
  * 
  */
 public function setTransient($strTransientKey, $vData, $intTime = null)
 {
     $sLockTransient = AmazonAutoLinks_Commons::TransientPrefix . '_' . md5("Lock_{$strTransientKey}");
     // Check if the transient is locked
     if (AmazonAutoLinks_WPUtilities::getTransient($sLockTransient) !== false) {
         return;
         // it means the cache is being modified right now in a different process.
     }
     // Set a lock flag transient that indicates the transient is being renewed.
     AmazonAutoLinks_WPUtilities::setTransient($sLockTransient, time(), AmazonAutoLinks_Utilities::getAllowedMaxExecutionTime(30, 30));
     // AmazonAutoLinks_Debug::logArray( 'set transient: ' . $strTransientKey );
     // Save the cache
     AmazonAutoLinks_WPUtilities::setTransient($strTransientKey, array('mod' => $intTime ? $intTime : time(), 'data' => $this->oEncrypt->encode($vData)));
     // no expiration by itself
     // AmazonAutoLinks_Debug::logArray( 'the transient is saved: ' . $strTransientKey );
     // AmazonAutoLinks_WPUtilities::deleteTransient( $sLockTransient );
 }
 /**
  * Fetches HTML body with the specified URL with caching functionality.
  * 
  */
 public function getHTML($strURL, $fUseFileGetContents = false)
 {
     // Check the transient first.
     $strTransient = $this->strHTMLCachePrefix . md5($strURL);
     $strHTMLBodyEncoded = AmazonAutoLinks_WPUtilities::getTransient($strTransient);
     if (false !== $strHTMLBodyEncoded) {
         return $this->oEncrypt->decode($strHTMLBodyEncoded);
     }
     // Fetch HTML.
     if ($fUseFileGetContents) {
         $strHTMLBody = file_get_contents($strURL);
     } else {
         $arrResponse = wp_remote_get($strURL, array('timeout' => 20, 'httpversion' => '1.1'));
         $strHTMLBody = wp_remote_retrieve_body($arrResponse);
     }
     // If failed or empty, return.
     if (empty($strHTMLBody)) {
         return $strHTMLBody;
     }
     // Encode the HTML string; otherwise, sometimes it gets broken.
     AmazonAutoLinks_WPUtilities::setTransient($strTransient, $this->oEncrypt->encode($strHTMLBody), 60 * 60 * 48);
     return $strHTMLBody;
 }
 public function validation_aal_add_search_unit_initial_search_settings($aInput, $aOldInput)
 {
     // validation_{page slug}_{tab slug}
     $fVerified = true;
     $arrErrors = array();
     $arrSearchOptions = $aInput['aal_add_search_unit']['search'];
     // Check the limitation.
     if ($this->oOption->isUnitLimitReached()) {
         $this->setFieldErrors(array('error'));
         // must set an field error array which does not yield empty so that it won't be redirected.
         $this->setSettingNotice(sprintf(__('Please upgrade to <A href="%1$s">Pro</a> to add more units! Make sure to empty the <a href="%2$s">trash box</a> to delete the units completely!', 'amazon-auto-links'), 'http://en.michaeluno.jp/amazon-auto-links-pro/', admin_url('edit.php?post_status=trash&post_type=' . AmazonAutoLinks_Commons::PostTypeSlug)));
         return $aOldInput;
     }
     // If the Access Key fields are present, it means the user has not set them yet in the Settings page.
     // In this case, just check if they are valid and if so, save them in the settings' option array. Otherwise, return an error.
     if (isset($arrSearchOptions['search_access_key'], $arrSearchOptions['search_access_key_secret'])) {
         $strPublicKey = $arrSearchOptions['search_access_key'];
         if (strlen($strPublicKey) != 20) {
             $arrErrors['search']['search_access_key'] = __('The Access Key ID must consist of 20 characters.', 'amazon-auto-links') . ': ' . $strPublicKey . ' ';
             $fVerified = false;
         }
         $strPrivateKey = $arrSearchOptions['search_access_key_secret'];
         if (strlen($strPrivateKey) != 40) {
             $arrErrors['search']['search_access_key_secret'] = __('The Secret Access Key must consist of 40 characters.', 'amazon-auto-links') . ': ' . $strPrivateKey . ' ';
             $fVerified = false;
         }
         // An invalid value is found.
         if (!$fVerified) {
             // Set the error array for the input fields.
             $this->setFieldErrors($arrErrors);
             $this->setSettingNotice(__('There was an error in your input.', 'amazon-auto-links'));
             return $aOldInput;
         }
         // Test authentication - browse the Books node in amazon.com.
         $oAmazonAPI = new AmazonAutoLinks_ProductAdvertisingAPI('com', $strPublicKey, $strPrivateKey);
         if (!$oAmazonAPI->test()) {
             $arrErrors['search']['search_access_key'] = __('Sent Value', 'amazon-auto-links') . ': ' . $strPublicKey;
             $arrErrors['search']['search_access_key_secret'] = __('Sent Value', 'amazon-auto-links') . ': ' . $strPrivateKey;
             $this->setFieldErrors($arrErrors);
             $this->setSettingNotice(__('Failed authentication.', 'amazon-auto-links'));
             $aOldInput;
         }
         // It is authenticated, so set the keys in the Settings option array.
         // Since the validation_ callbacks internally merge with the framework's property option array,
         // modify the property array, NOT the option object that plugin creates.
         $this->oProps->arrOptions['aal_settings']['authentication_keys']['access_key'] = $strPublicKey;
         $this->oProps->arrOptions['aal_settings']['authentication_keys']['access_key_secret'] = $strPrivateKey;
     }
     if (empty($arrSearchOptions['search_associate_id'])) {
         $arrErrors['search']['search_associate_id'] = __('The associate ID cannot be empty.', 'amazon-auto-links');
         $fVerified = false;
     }
     // An invalid value is found.
     if (!$fVerified) {
         // Set the error array for the input fields.
         $this->setFieldErrors($arrErrors);
         $this->setSettingNotice(__('There was an error in your input.', 'amazon-auto-links'));
         return $aOldInput;
     }
     // Drop the sections.
     $_aNewFields = array();
     foreach ($aInput['aal_add_search_unit'] as $strSection => $arrFields) {
         $_aNewFields = $_aNewFields + $arrFields;
     }
     // Remove the search_ prefix in the keys.
     $_aSanitizedFields = array();
     foreach ($_aNewFields as $strKey => $vValue) {
         $_aSanitizedFields[preg_replace('/^search_/', '', $strKey)] = $vValue;
     }
     // Set the unit type based on the chosen one.
     // Redirect to the appropriate page by the search type.
     switch ($_aSanitizedFields['Operation']) {
         case 'ItemSearch':
             $_aSanitizedFields['unit_type'] = 'search';
             $sTabSlug = 'search_products';
             break;
         case 'ItemLookup':
             $_aSanitizedFields['unit_type'] = 'item_lookup';
             $sTabSlug = 'item_lookup';
             break;
         case 'SimilarityLookup':
             $_aSanitizedFields['unit_type'] = 'similarity_lookup';
             $sTabSlug = 'similarity_lookup';
             break;
     }
     // Save the transient
     $arrTempUnitOptions = (array) AmazonAutoLinks_WPUtilities::getTransient('AAL_CreateUnit_' . $_aSanitizedFields['transient_id']);
     $aSavingUnitOptions = AmazonAutoLinks_Utilities::uniteArrays($_aSanitizedFields, $arrTempUnitOptions);
     AmazonAutoLinks_WPUtilities::setTransient('AAL_CreateUnit_' . $_aSanitizedFields['transient_id'], $aSavingUnitOptions, 60 * 10 * 6 * 24);
     // Go to the next page.
     die(wp_redirect(add_query_arg(array('tab' => $sTabSlug, 'transient_id' => $_aSanitizedFields['transient_id']) + $_GET, $_aSanitizedFields['bounce_url'])));
 }
 /**
  * A callback for the accessSiteAtShutDown() method.
  * 
  * @since            1.0.0
  */
 public static function _replyToAccessSite()
 {
     // Retrieve the plugin scheduled tasks array.
     $_sTransientName = md5(get_class());
     $_aTasks = AmazonAutoLinks_WPUtilities::getTransient($_sTransientName);
     $_aTasks = $_aTasks ? $_aTasks : array();
     $_nNow = microtime(true);
     // Check the excessive background call protection interval
     if (!self::$_fIgnoreLock) {
         $_nCalled = isset($_aTasks['called']) ? $_aTasks['called'] : 0;
         if ($_nCalled + self::$_iLockBackgroundCallInterval > $_nNow) {
             return;
             // if it's called within 10 seconds from the last time of calling this method, do nothing to avoid excessive calls.
         }
     }
     // Renew the called time.
     $_aFlagKeys = array('called' => $_nNow);
     AmazonAutoLinks_WPUtilities::setTransient($_sTransientName, $_aFlagKeys + $_aTasks, self::getAllowedMaxExecutionTime());
     // set a locked key so it prevents duplicated function calls due to too many calls caused by simultaneous accesses.
     // Compose a GET query array
     $_aGet = self::$_aGet;
     if (defined('WP_DEBUG')) {
         $_aGet['debug'] = WP_DEBUG;
     }
     unset($_aGet[0]);
     // Load the site in the background.
     wp_remote_get(site_url('?' . http_build_query($_aGet)), array('timeout' => 0.01, 'sslverify' => false, 'cookies' => $_aFlagKeys + array($_sTransientName => true)));
 }