/** * Execute the action */ public function execute() { parent::execute(); // get parameters $categoryTitle = trim(\SpoonFilter::getPostValue('value', null, '', 'string')); // validate if ($categoryTitle === '') { $this->output(self::BAD_REQUEST, null, BL::err('TitleIsRequired')); } else { // get the data // build array $item['title'] = \SpoonFilter::htmlspecialchars($categoryTitle); $item['language'] = BL::getWorkingLanguage(); $meta['keywords'] = $item['title']; $meta['keywords_overwrite'] = 'N'; $meta['description'] = $item['title']; $meta['description_overwrite'] = 'N'; $meta['title'] = $item['title']; $meta['title_overwrite'] = 'N'; $meta['url'] = BackendBlogModel::getURLForCategory(\SpoonFilter::urlise($item['title'])); // update $item['id'] = BackendBlogModel::insertCategory($item, $meta); // output $this->output(self::OK, $item, vsprintf(BL::msg('AddedCategory'), array($item['title']))); } }
/** * Execute the action */ public function execute() { parent::execute(); // get parameters $id = SpoonFilter::getPostValue('id', null, 0, 'int'); $tag = trim(SpoonFilter::getPostValue('value', null, '', 'string')); // validate if ($id === 0) { $this->output(self::BAD_REQUEST, null, 'no id provided'); } if ($tag === '') { $this->output(self::BAD_REQUEST, null, BL::err('NameIsRequired')); } // check if tag exists if (BackendTagsModel::existsTag($tag)) { $this->output(self::BAD_REQUEST, null, BL::err('TagAlreadyExists')); } // build array $item['id'] = $id; $item['tag'] = SpoonFilter::htmlspecialchars($tag); $item['url'] = BackendTagsModel::getURL(SpoonFilter::urlise(SpoonFilter::htmlspecialcharsDecode($item['tag'])), $id); // update BackendTagsModel::update($item); // output $this->output(self::OK, $item, vsprintf(BL::msg('Edited'), array($item['tag']))); }
/** * Adds Google UTM GET Parameters to all anchor links in the mailing * * @return string * @param string $HTML The HTML wherin the parameters will be added. */ private function addUTMParameters($HTML) { // init var $matches = array(); // search for all hrefs preg_match_all('/href="(.*)"/isU', $HTML, $matches); // reserve searhc vars $search = array(); $replace = array(); // check if we have matches if (!isset($matches[1]) || empty($matches[1])) { return $HTML; } // build the google vars query $params['utm_source'] = 'mailmotor'; $params['utm_medium'] = 'email'; $params['utm_campaign'] = SpoonFilter::urlise($this->mailing['name']); // build google vars query $googleQuery = http_build_query($params); // loop the matches foreach ($matches[1] as $match) { // ignore # if (strpos($match, '#') > -1) { continue; } // add results to search/replace stack $search[] = 'href="' . $match . '"'; $replace[] = 'href="' . $match . (strpos($match, '?') !== false ? '&' : '?') . $googleQuery . '"'; } // replace the content HTML with the replace values return str_replace($search, $replace, $HTML); }
/** * Execute the action */ public function execute() { parent::execute(); $isGod = BackendAuthentication::getUser()->isGod(); // get possible languages if ($isGod) { $possibleLanguages = array_unique(array_merge(BL::getWorkingLanguages(), BL::getInterfaceLanguages())); } else { $possibleLanguages = BL::getWorkingLanguages(); } // get parameters $language = SpoonFilter::getPostValue('language', array_keys($possibleLanguages), null, 'string'); $module = SpoonFilter::getPostValue('module', BackendModel::getModules(), null, 'string'); $name = SpoonFilter::getPostValue('name', null, null, 'string'); $type = SpoonFilter::getPostValue('type', BackendModel::getDB()->getEnumValues('locale', 'type'), null, 'string'); $application = SpoonFilter::getPostValue('application', array('backend', 'frontend'), null, 'string'); $value = SpoonFilter::getPostValue('value', null, null, 'string'); // validate values if (trim($value) == '' || $language == '' || $module == '' || $type == '' || $application == '' || $application == 'frontend' && $module != 'core') { $error = BL::err('InvalidValue'); } // in case this is a 'act' type, there are special rules concerning possible values if ($type == 'act' && !isset($error)) { if (urlencode($value) != SpoonFilter::urlise($value)) { $error = BL::err('InvalidActionValue', $this->getModule()); } } // no error? if (!isset($error)) { // build item $item['language'] = $language; $item['module'] = $module; $item['name'] = $name; $item['type'] = $type; $item['application'] = $application; $item['value'] = $value; $item['edited_on'] = BackendModel::getUTCDate(); $item['user_id'] = BackendAuthentication::getUser()->getUserId(); // does the translation exist? if (BackendLocaleModel::existsByName($name, $type, $module, $language, $application)) { // add the id to the item $item['id'] = (int) BackendLocaleModel::getByName($name, $type, $module, $language, $application); // update in db BackendLocaleModel::update($item); } else { // insert in db BackendLocaleModel::insert($item); } // output OK $this->output(self::OK); } else { $this->output(self::ERROR, null, $error); } }
/** * Retrieve the unique url for an item * * @param string $url * @param int[optional] $id * @return string */ public static function getUrl($url, $id = null) { // redefine Url $url = \SpoonFilter::urlise((string) $url); // get db $db = BackendModel::get('database'); // new item if ($id === null) { $numberOfItems = (int) $db->getVar('SELECT 1 FROM media AS i INNER JOIN meta AS m ON i.meta_id = m.id WHERE i.language = ? AND m.url = ? LIMIT 1', array(Language::getWorkingLanguage(), $url)); // already exists if ($numberOfItems != 0) { // add number $url = BackendModel::addNumber($url); // try again return self::getUrl($url); } } else { $numberOfItems = (int) $db->getVar('SELECT 1 FROM media AS i INNER JOIN meta AS m ON i.meta_id = m.id WHERE i.language = ? AND m.url = ? AND i.id != ? LIMIT 1', array(Language::getWorkingLanguage(), $url, $id)); // already exists if ($numberOfItems != 0) { // add number $url = BackendModel::addNumber($url); // try again return self::getUrl($url, $id); } } // return the unique Url! return $url; }
/** * Retrieve the unique URL for a category * * @param string $url * @param int[optional] $id The id of the category to ignore. * @return string */ public static function getURLForCategory($url, $id = null) { $url = SpoonFilter::urlise((string) $url); $db = BackendModel::getDB(); // new category if ($id === null) { // get number of categories with this URL $number = (int) $db->getVar('SELECT COUNT(i.id) FROM faq_categories AS i INNER JOIN meta AS m ON i.meta_id = m.id WHERE i.language = ? AND m.url = ?', array(BL::getWorkingLanguage(), $url)); // already exists if ($number != 0) { $url = BackendModel::addNumber($url); return self::getURLForCategory($url); } } else { // get number of items with this URL $number = (int) $db->getVar('SELECT COUNT(i.id) FROM faq_categories AS i INNER JOIN meta AS m ON i.meta_id = m.id WHERE i.language = ? AND m.url = ? AND i.id != ?', array(BL::getWorkingLanguage(), $url, $id)); // already exists if ($number != 0) { $url = BackendModel::addNumber($url); return self::getURLForCategory($url, $id); } } return $url; }
/** * Process the XML and treat it as a blogpost * * @return bool * @param SimpleXMLElement $xml The XML to process. */ private function processXMLAsPost(SimpleXMLElement $xml) { // init var $postID = substr((string) $xml->id, mb_strpos((string) $xml->id, 'post-') + 5); // validate if ($postID == '') { return false; } if ((string) $xml->title == '') { return false; } // build item $item['id'] = (int) BackendBlogModel::getMaximumId() + 1; $item['user_id'] = BackendAuthentication::getUser()->getUserId(); $item['hidden'] = 'N'; $item['allow_comments'] = 'Y'; $item['num_comments'] = 0; $item['status'] = 'active'; $item['language'] = BL::getWorkingLanguage(); $item['publish_on'] = BackendModel::getUTCDate(null, strtotime((string) $xml->published)); $item['created_on'] = BackendModel::getUTCDate(null, strtotime((string) $xml->published)); $item['edited_on'] = BackendModel::getUTCDate(null, strtotime((string) $xml->updated)); $item['category_id'] = 1; $item['title'] = (string) $xml->title; $item['text'] = (string) $xml->content; // set drafts hidden if (strtotime((string) $xml->published) > time()) { $item['hidden'] = 'Y'; $item['status'] = 'draft'; } // build meta $meta = array(); $meta['keywords'] = $item['title']; $meta['keywords_overwrite'] = 'N'; $meta['description'] = $item['title']; $meta['description_overwrite'] = 'N'; $meta['title'] = $item['title']; $meta['title_overwrite'] = 'N'; $meta['url'] = BackendBlogModel::getURL(SpoonFilter::urlise($item['title'])); $meta['url_overwrite'] = 'N'; // replace f****d up links $item['text'] = preg_replace('|<a(.*)onblur="(.*)"(.*)>|Ui', '<a$1$3>', $item['text']); // fix images $item['text'] = preg_replace('|<img(.*)border="(.*)"(.*)>|Ui', '<img$1$3>', $item['text']); // remove inline styles $item['text'] = preg_replace('|<(.*)style="(.*)"(.*)>|Ui', '<$1$3>', $item['text']); // whitespace $item['text'] = preg_replace('|\\s{2,}|', ' ', $item['text']); // cleanup $search = array('<br /><br />', '<div><br /></div>', '<div>', '</div>', '<i>', '</i>', '<b>', '</b>', '<p><object', '</object></p>', '<p><p>', '</p></p>', '...'); $replace = array('</p><p>', '</p><p>', '', '', '<em>', '</em>', '<strong>', '</strong>', '<object', '</object>', '<p>', '</p>', '…'); // cleanup $item['text'] = '<p>' . str_replace($search, $replace, SpoonFilter::htmlentitiesDecode($item['text'])) . '</p>'; // get images $matches = array(); preg_match_all('/<img.*src="(.*)".*\\/>/Ui', $item['text'], $matches); // any images? if (isset($matches[1]) && !empty($matches[1])) { // init var $imagesPath = FRONTEND_FILES_PATH . '/userfiles/images/blog'; $imagesURL = FRONTEND_FILES_URL . '/userfiles/images/blog'; // create dir if needed if (!SpoonDirectory::exists($imagesPath)) { SpoonDirectory::create($imagesPath); } // loop matches foreach ($matches[1] as $key => $file) { // get file info $fileInfo = SpoonFile::getInfo($file); // init var $destinationFile = $item['id'] . '_' . $fileInfo['basename']; try { // download SpoonFile::download($file, $imagesPath . '/' . $destinationFile); // replace the old URL with the new one $item['text'] = str_replace($file, $imagesURL . '/' . $destinationFile, $item['text']); } catch (Exception $e) { // ignore } } } // get links $matches = array(); preg_match_all('/<a.*href="(.*)".*\\/>/Ui', $item['text'], $matches); // any images? if (isset($matches[1]) && !empty($matches[1])) { // loop matches foreach ($matches[1] as $key => $file) { // get new link $replaceWith = self::download($file, $item['id']); // should we replace? if ($replaceWith !== false) { // replace the old URL with the new one $item['text'] = str_replace($file, $replaceWith, $item['text']); } } } // insert meta $item['meta_id'] = BackendModel::getDB(true)->insert('meta', $meta); // insert BackendBlogModel::insert($item); // store the post $this->newIds[$postID] = $item['id']; // get tags $tags = array(); // loop categories foreach ($xml->category as $category) { // is this a tag? if so add it if ((string) $category['scheme'] == 'http://www.blogger.com/atom/ns#') { $tags[] = (string) $category['term']; } } // any tags? if (!empty($tags)) { BackendTagsModel::saveTags($item['id'], implode(',', $tags), $this->getModule()); } // return return true; }
/** * Get a unique URL for a tag * * @param string $URL The URL to use as a base. * @param int[optional] $id The ID to ignore. * @return string */ public static function getURL($URL, $id = null) { $URL = SpoonFilter::urlise((string) $URL); $language = BL::getWorkingLanguage(); // get db $db = BackendModel::getDB(); // no specific id if ($id === null) { // get number of tags with the specified url $number = (int) $db->getVar('SELECT COUNT(i.id) FROM tags AS i WHERE i.url = ? AND i.language = ?', array($URL, $language)); // there are items so, call this method again. if ($number != 0) { // add a number $URL = BackendModel::addNumber($URL); // recall this method, but with a new url $URL = self::getURL($URL, $id); } } else { // redefine $id = (int) $id; // get number of tags with the specified url $number = (int) $db->getVar('SELECT COUNT(i.id) FROM tags AS i WHERE i.url = ? AND i.language = ? AND i.id != ?', array($URL, $language, $id)); // there are items so, call this method again. if ($number != 0) { // add a number $URL = BackendModel::addNumber($URL); // recall this method, but with a new url $URL = self::getURL($URL, $id); } } return $URL; }
/** * Adds an email to the queue. * * @return int The id of the inserted mail. * @param string $subject The subject for the email. * @param string $template The template to use. * @param array[optional] $variables Variables that should be assigned in the email. * @param string[optional] $toEmail The to-address for the email. * @param string[optional] $toName The to-name for the email. * @param string[optional] $fromEmail The from-address for the mail. * @param string[optional] $fromName The from-name for the mail. * @param string[optional] $replyToEmail The replyto-address for the mail. * @param string[optional] $replyToName The replyto-name for the mail. * @param bool[optional] $queue Should the mail be queued? * @param int[optional] $sendOn When should the email be send, only used when $queue is true. * @param bool[optional] $isRawHTML If this is true $template will be handled as raw HTML, so no parsing of $variables is done. * @param string[optional] $plainText The plain text version. * @param array[optional] $attachments Paths to attachments to include. */ public static function addEmail($subject, $template, array $variables = null, $toEmail = null, $toName = null, $fromEmail = null, $fromName = null, $replyToEmail = null, $replyToName = null, $queue = false, $sendOn = null, $isRawHTML = false, $plainText = null, array $attachments = null) { // redefine $subject = (string) strip_tags($subject); $template = (string) $template; // set defaults $to = FrontendModel::getModuleSetting('core', 'mailer_to'); $from = FrontendModel::getModuleSetting('core', 'mailer_from'); $replyTo = FrontendModel::getModuleSetting('core', 'mailer_reply_to'); $utm = array('utm_source' => 'mail', 'utm_medium' => 'email', 'utm_campaign' => SpoonFilter::urlise($subject)); // set recipient/sender headers $email['to_email'] = empty($toEmail) ? (string) $to['email'] : $toEmail; $email['to_name'] = empty($toName) ? (string) $to['name'] : $toName; $email['from_email'] = empty($fromEmail) ? (string) $from['email'] : $fromEmail; $email['from_name'] = empty($fromName) ? (string) $from['name'] : $fromName; $email['reply_to_email'] = empty($replyToEmail) ? (string) $replyTo['email'] : $replyToEmail; $email['reply_to_name'] = empty($replyToName) ? (string) $replyTo['name'] : $replyToName; // validate if (!empty($email['to_email']) && !SpoonFilter::isEmail($email['to_email'])) { throw new FrontendException('Invalid e-mail address for recipient.'); } if (!empty($email['from_email']) && !SpoonFilter::isEmail($email['from_email'])) { throw new FrontendException('Invalid e-mail address for sender.'); } if (!empty($email['reply_to_email']) && !SpoonFilter::isEmail($email['reply_to_email'])) { throw new FrontendException('Invalid e-mail address for reply-to address.'); } // build array $email['subject'] = SpoonFilter::htmlentitiesDecode($subject); if ($isRawHTML) { $email['html'] = $template; } else { $email['html'] = self::getTemplateContent($template, $variables); } if ($plainText !== null) { $email['plain_text'] = $plainText; } $email['created_on'] = FrontendModel::getUTCDate(); // init var $matches = array(); // get internal links preg_match_all('|href="/(.*)"|i', $email['html'], $matches); // any links? if (!empty($matches[0])) { // init vars $search = array(); $replace = array(); // loop the links foreach ($matches[0] as $key => $link) { $search[] = $link; $replace[] = 'href="' . SITE_URL . '/' . $matches[1][$key] . '"'; } // replace $email['html'] = str_replace($search, $replace, $email['html']); } // init var $matches = array(); // get internal urls preg_match_all('|src="/(.*)"|i', $email['html'], $matches); // any links? if (!empty($matches[0])) { // init vars $search = array(); $replace = array(); // loop the links foreach ($matches[0] as $key => $link) { $search[] = $link; $replace[] = 'src="' . SITE_URL . '/' . $matches[1][$key] . '"'; } // replace $email['html'] = str_replace($search, $replace, $email['html']); } // init var $matches = array(); // match links preg_match_all('/href="(http:\\/\\/(.*))"/iU', $email['html'], $matches); // any links? if (isset($matches[0]) && !empty($matches[0])) { // init vars $searchLinks = array(); $replaceLinks = array(); // loop old links foreach ($matches[1] as $i => $link) { $searchLinks[] = $matches[0][$i]; $replaceLinks[] = 'href="' . FrontendModel::addURLParameters($link, $utm) . '"'; } // replace $email['html'] = str_replace($searchLinks, $replaceLinks, $email['html']); } // attachments added if (!empty($attachments)) { // add attachments one by one foreach ($attachments as $attachment) { // only add existing files if (SpoonFile::exists($attachment)) { $email['attachments'][] = $attachment; } } // serialize :) if (!empty($email['attachments'])) { $email['attachments'] = serialize($email['attachments']); } } // set send date if ($queue) { if ($sendOn === null) { $email['send_on'] = FrontendModel::getUTCDate('Y-m-d H') . ':00:00'; } else { $email['send_on'] = FrontendModel::getUTCDate('Y-m-d H:i:s', (int) $sendOn); } } // insert the email into the database $id = FrontendModel::getDB(true)->insert('emails', $email); // trigger event FrontendModel::triggerEvent('core', 'after_email_queued', array('id' => $id)); // if queue was not enabled, send this mail right away if (!$queue) { self::send($id); } // return return $id; }
/** * Insert meta for an item in the database * * @param array $data * * @return int */ public static function insertMeta(array $data) { //--Replace special characters $data["url"] = strtr($data["url"], "ŠŒŽšœžŸ¥µÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿ", "SOZsozYYuAAAAAAACEEEEIIIIDNOOOOOOUUUUYsaaaaaaaceeeeiiiionoooooouuuuyy"); $data["url"] = str_replace(".", "", \SpoonFilter::urlise($data["url"])); //--Replace the values with utf8 foreach ($data as &$value) { $value = utf8_encode($value); } $data['url'] = BackendAddressesModel::checkUrl($data['url']); return (int) BackendModel::getContainer()->get('database')->insert('meta', $data); }
/** * Retrieve the unique URL for a category * * @param string $url * @param int [optional] $id The id of the category to ignore. * @return string */ public static function getURLForBrand($url, $id = null) { $url = \SpoonFilter::urlise((string) $url); $db = BackendModel::getContainer()->get('database'); // new category if ($id === null) { if ((bool) $db->getVar('SELECT 1 FROM catalog_brands AS i INNER JOIN meta AS m ON i.meta_id = m.id WHERE m.url = ? LIMIT 1', array($url))) { $url = BackendModel::addNumber($url); return self::getURLForCategory($url); } } else { // current category should be excluded if ((bool) $db->getVar('SELECT 1 FROM catalog_brands AS i INNER JOIN meta AS m ON i.meta_id = m.id WHERE m.url = ? AND i.id != ? LIMIT 1', array($url, $id))) { $url = BackendModel::addNumber($url); return self::getURLForCategory($url, $id); } } return $url; }
public function parse() { // more matches to be found than? if ($this->pagination['num_items'] > count($this->items)) { // remove last result (to add this reference) array_pop($this->items); // add reference to full search results page $this->items[] = array('title' => FL::lbl('More'), 'text' => FL::msg('MoreResults'), 'full_url' => FrontendNavigation::getURLForBlock('search') . '?form=search&q=' . $this->term); } // format data foreach ($this->items as &$item) { // full url is set? if (!isset($item['full_url'])) { continue; } // build utm array $utm['utm_source'] = SpoonFilter::urlise(FrontendModel::getModuleSetting('core', 'site_title_' . FRONTEND_LANGUAGE, SITE_DEFAULT_TITLE)); $utm['utm_medium'] = 'fork-search'; $utm['utm_term'] = $this->term; // get parameters in url already if (strpos($item['full_url'], '?') !== false) { $glue = '&'; } else { $glue = '?'; } // add utm to url $item['full_url'] .= $glue . http_build_query($utm, '', '&'); // format description $item['text'] = !empty($item['text']) ? mb_strlen($item['text']) > $this->length ? mb_substr(strip_tags($item['text']), 0, $this->length, SPOON_CHARSET) . '…' : $item['text'] : ''; } // output $this->output(self::OK, $this->items); }
/** * Retrieve the unique URL for a category * * @return string * @param string $URL The string wheron the URL will be based. * @param int[optional] $id The id of the category to ignore. */ public static function getURLForCategory($URL, $id = null) { // redefine URL $URL = SpoonFilter::urlise((string) $URL); // get db $db = BackendModel::getDB(); // new category if ($id === null) { // get number of categories with this URL $number = (int) $db->getVar('SELECT COUNT(i.id) FROM blog_categories AS i INNER JOIN meta AS m ON i.meta_id = m.id WHERE i.language = ? AND m.url = ?', array(BL::getWorkingLanguage(), $URL)); // already exists if ($number != 0) { // add number $URL = BackendModel::addNumber($URL); // try again return self::getURLForCategory($URL); } } else { // get number of items with this URL $number = (int) $db->getVar('SELECT COUNT(i.id) FROM blog_categories AS i INNER JOIN meta AS m ON i.meta_id = m.id WHERE i.language = ? AND m.url = ? AND i.id != ?', array(BL::getWorkingLanguage(), $URL, $id)); // already exists if ($number != 0) { // add number $URL = BackendModel::addNumber($URL); // try again return self::getURLForCategory($URL, $id); } } // return the unique URL! return $URL; }
/** * Validate the form. */ private function validateForm() { // is the form submitted if ($this->frm->isSubmitted()) { // get fields $txtDisplayName = $this->frm->getField('display_name'); $txtFirstName = $this->frm->getField('first_name'); $txtLastName = $this->frm->getField('last_name'); $txtCity = $this->frm->getField('city'); $ddmCountry = $this->frm->getField('country'); $ddmGender = $this->frm->getField('gender'); $ddmDay = $this->frm->getField('day'); $ddmMonth = $this->frm->getField('month'); $ddmYear = $this->frm->getField('year'); // get number of display name changes $nameChanges = (int) FrontendProfilesModel::getSetting($this->profile->getId(), 'display_name_changes'); // has there been a valid display name change request? if ($this->profile->getDisplayName() !== $txtDisplayName->getValue() && $nameChanges <= FrontendProfilesModel::MAX_DISPLAY_NAME_CHANGES) { // display name filled in? if ($txtDisplayName->isFilled(FL::getError('FieldIsRequired'))) { // display name exists? if (FrontendProfilesModel::existsDisplayName($txtDisplayName->getValue(), $this->profile->getId())) { // set error $txtDisplayName->addError(FL::getError('DisplayNameExists')); } } } // birthdate is not required but if one is filled we need all if ($ddmMonth->isFilled() || $ddmDay->isFilled() || $ddmYear->isFilled()) { // valid birth date? if (!checkdate($ddmMonth->getValue(), $ddmDay->getValue(), $ddmYear->getValue())) { // set error $ddmYear->addError(FL::getError('DateIsInvalid')); } } // validate avatar when given $this->frm->getField('avatar')->isFilled(); // no errors if ($this->frm->isCorrect()) { // init $values = array(); $settings = array(); // has there been a valid display name change request? if ($this->profile->getDisplayName() !== $txtDisplayName->getValue() && $nameChanges <= FrontendProfilesModel::MAX_DISPLAY_NAME_CHANGES) { // get display name value $values['display_name'] = $txtDisplayName->getValue(); // update url based on the new display name $values['url'] = FrontendProfilesModel::getUrl($txtDisplayName->getValue(), $this->profile->getId()); // update display name count $settings['display_name_changes'] = $nameChanges + 1; } // update values if (!empty($values)) { FrontendProfilesModel::update($this->profile->getId(), $values); } // build settings $settings['first_name'] = $txtFirstName->getValue(); $settings['last_name'] = $txtLastName->getValue(); $settings['city'] = $txtCity->getValue(); $settings['country'] = $ddmCountry->getValue(); $settings['gender'] = $ddmGender->getValue(); // birthday is filled in if ($ddmYear->isFilled()) { // mysql format $settings['birth_date'] = $ddmYear->getValue() . '-'; $settings['birth_date'] .= str_pad($ddmMonth->getValue(), 2, '0', STR_PAD_LEFT) . '-'; $settings['birth_date'] .= str_pad($ddmDay->getValue(), 2, '0', STR_PAD_LEFT); } else { // not filled in $settings['birth_date'] = null; } // avatar $settings['avatar'] = $this->profile->getSetting('avatar'); // create new filename if ($this->frm->getField('avatar')->isFilled()) { // field value $settings['avatar'] = \SpoonFilter::urlise($this->profile->getDisplayName()) . '.' . $this->frm->getField('avatar')->getExtension(); // move the file $this->frm->getField('avatar')->generateThumbnails(FRONTEND_FILES_PATH . '/Profiles/Avatars/', $settings['avatar']); } // save settings $this->profile->setSettings($settings); // trigger event FrontendModel::triggerEvent('Profiles', 'after_saved_settings', array('id' => $this->profile->getId())); // redirect $this->redirect(SITE_URL . FrontendNavigation::getURLForBlock('Profiles', 'Settings') . '?sent=true'); } else { $this->tpl->assign('updateSettingsHasFormError', true); } } }
/** * Default constructor. * * @param string $title The title for the item. * @param string $link The link for the item. * @param string $description The content for the item. */ public function __construct($title, $link, $description) { // set UTM-campaign $this->utm['utm_campaign'] = SpoonFilter::urlise($title); // convert to plain text $description = FrontendModel::convertToPlainText($description); // set title $this->setSummary($title); // set url $this->setUrl(FrontendModel::addURLParameters($link, $this->utm)); // set description $this->setDescription($this->processLinks($description)); // set identifier $this->setUniqueIdentifier(md5($link)); // build properties $properties['X-GOOGLE-CALENDAR-CONTENT-TITLE'] = $title; $properties['X-GOOGLE-CALENDAR-CONTENT-ICON'] = SITE_URL . '/favicon.ico'; $properties['X-GOOGLE-CALENDAR-CONTENT-URL'] = $this->getUrl(); // set properties $this->setXProperties($properties); }
/** * Generate an url, using the predefined callback. * * @param string $URL The base-url to start from. * @return string */ public function generateURL($URL) { // validate (check if the function exists) if (!is_callable(array($this->callback['class'], $this->callback['method']))) { throw new BackendException('The callback-method doesn\'t exist.'); } // build parameters for use in the callback $parameters[] = SpoonFilter::urlise($URL); // add parameters set by user if (!empty($this->callback['parameters'])) { foreach ($this->callback['parameters'] as $parameter) { $parameters[] = $parameter; } } // get the real url return call_user_func_array(array($this->callback['class'], $this->callback['method']), $parameters); }
/** * Parse the data into the template */ private function parse() { // parse the form $this->frm->parse($this->tpl); // no search term = no search if (!$this->term) { return; } // loop items foreach ($this->items as &$item) { // full url is set? if (!isset($item['full_url'])) { continue; } // build utm array $utm['utm_source'] = SpoonFilter::urlise(FrontendModel::getModuleSetting('core', 'site_title_' . FRONTEND_LANGUAGE, SITE_DEFAULT_TITLE)); $utm['utm_medium'] = 'fork-search'; $utm['utm_term'] = $this->term; // get parameters in url already if (strpos($item['full_url'], '?') !== false) { $glue = '&'; } else { $glue = '?'; } // add utm to url $item['full_url'] .= $glue . http_build_query($utm, '', '&'); } // assign articles $this->tpl->assign('searchResults', $this->items); $this->tpl->assign('searchTerm', $this->term); // parse the pagination $this->parsePagination(); }
/** * Validate the form * * @return void */ private function validateForm() { // is the form submitted? if ($this->frm->isSubmitted()) { // cleanup the submitted fields, ignore fields that were added by hackers $this->frm->cleanupFields(); // shorten fields $fileCSV = $this->frm->getField('csv'); $chkGroups = $this->frm->getField('groups'); // validate fields $fileCSV->isFilled(BL::err('CSVIsRequired')); // convert the CSV file to an array $csv = $fileCSV->isFilled() ? SpoonFileCSV::fileToArray($fileCSV->getTempFileName()) : null; // check if the csv is valid if ($csv === false || empty($csv) || !isset($csv[0])) { $fileCSV->addError(BL::err('InvalidCSV')); } // there was a csv file found if (!empty($csv)) { // fetch the columns of the first row $columns = array_keys($csv[0]); // loop the columns foreach ($csv as $row) { // fetch the row columns $rowColumns = array_keys($row); // check if the arrays match if ($rowColumns != $columns) { // add an error to the CSV files $fileCSV->addError(BL::err('InvalidCSV')); // exit loop break; } } } // get values $values = $this->frm->getValues(); // check if at least one recipient group is chosen if (empty($values['groups'])) { $chkGroups->addError(BL::err('ChooseAtLeastOneGroup')); } // no errors? if ($this->frm->isCorrect()) { // convert the CSV file to an array, and fetch the group's CM ID $csv = SpoonFileCSV::fileToArray($fileCSV->getTempFileName(), null, null, ';', '"'); // process our import, and get the failed subscribers $failedSubscribers = $this->processImport($csv, $values['groups']); // show a detailed report $this->tpl->assign('import', false); // no failed subscribers found if (empty($failedSubscribers)) { // trigger event BackendModel::triggerEvent($this->getModule(), 'after_import_address'); // redirect to success message $this->redirect(BackendModel::createURLForAction('addresses') . '&report=imported-addresses&var[]=' . count($csv) . '&var[]=' . count($values['groups'])); } else { // write a CSV file to the cache $csvFile = 'import-report-' . SpoonFilter::urlise(BackendModel::getUTCDate()) . '.csv'; SpoonFileCSV::arrayToFile(BACKEND_CACHE_PATH . '/mailmotor/' . $csvFile, $failedSubscribers, null, null, ';', '"'); // trigger event BackendModel::triggerEvent($this->getModule(), 'after_import_address_with_failed_items', array('failed' => $failedSubscribers)); // redirect to failed message with an additional parameter to display a download link to the report-csv form cache. $this->redirect(BackendModel::createURLForAction('addresses') . '&error=imported-addresses&var[]=' . count($csv) . '&var[]=' . count($values['groups']) . '&var[]=' . count($failedSubscribers) . '&csv=' . $csvFile); } } } }
/** * Validates the form * It checks if there is a value when a checkbox is checked * * @return void */ public function validate() { // no callback set by user? if (empty($this->callback)) { // build class- & method-name $className = 'Backend' . SpoonFilter::toCamelCase($this->URL->getModule()) . 'Model'; $methodName = 'getURL'; // set $this->setUrlCallback($className, $methodName); } // page title overwrite is checked if ($this->frm->getField('page_title_overwrite')->isChecked()) { $this->frm->getField('page_title')->isFilled(BL::err('FieldIsRequired')); } // meta description overwrite is checked if ($this->frm->getField('meta_description_overwrite')->isChecked()) { $this->frm->getField('meta_description')->isFilled(BL::err('FieldIsRequired')); } // meta keywords overwrite is checked if ($this->frm->getField('meta_keywords_overwrite')->isChecked()) { $this->frm->getField('meta_keywords')->isFilled(BL::err('FieldIsRequired')); } // URL overwrite is checked if ($this->frm->getField('url_overwrite')->isChecked()) { // filled $this->frm->getField('url')->isFilled(BL::err('FieldIsRequired')); // fetch url $URL = SpoonFilter::urlise($this->frm->getField('url')->getValue()); // build parameters for use in the callback $parameters[] = $URL; // add parameters set by user if (!empty($this->callback['parameters'])) { foreach ($this->callback['parameters'] as $parameter) { $parameters[] = $parameter; } } // get the real url $generatedUrl = call_user_func_array(array($this->callback['class'], $this->callback['method']), $parameters); // check if urls are different if ($URL != $generatedUrl) { $this->frm->getField('url')->addError(BL::err('URLAlreadyExists')); } } // if the form was submitted correctly the data array should be populated if ($this->frm->isCorrect()) { // no callback set by user? if (empty($this->callback)) { // build class- & method-name $className = 'Backend' . SpoonFilter::toCamelCase($this->URL->getModule()) . 'Model'; $methodName = 'getURL'; // set $this->setUrlCallback($className, $methodName); } // get meta keywords if ($this->frm->getField('meta_keywords_overwrite')->isChecked()) { $keywords = $this->frm->getField('meta_keywords')->getValue(); } else { $keywords = $this->frm->getField($this->baseFieldName)->getValue(); } // get meta description if ($this->frm->getField('meta_description_overwrite')->isChecked()) { $description = $this->frm->getField('meta_description')->getValue(); } else { $description = $this->frm->getField($this->baseFieldName)->getValue(); } // get page title if ($this->frm->getField('page_title_overwrite')->isChecked()) { $title = $this->frm->getField('page_title')->getValue(); } else { $title = $this->frm->getField($this->baseFieldName)->getValue(); } // get URL if ($this->frm->getField('url_overwrite')->isChecked()) { $URL = SpoonFilter::urlise(SpoonFilter::htmlspecialcharsDecode($this->frm->getField('url')->getValue())); } else { $URL = SpoonFilter::urlise(SpoonFilter::htmlspecialcharsDecode($this->frm->getField($this->baseFieldName)->getValue())); } // build parameters for use in the callback $parameters[] = $URL; // add parameters set by user if (!empty($this->callback['parameters'])) { foreach ($this->callback['parameters'] as $parameter) { $parameters[] = $parameter; } } // get the real URL $URL = call_user_func_array(array($this->callback['class'], $this->callback['method']), $parameters); // get meta custom if ($this->custom && $this->frm->getField('meta_custom')->isFilled()) { $custom = $this->frm->getField('meta_custom')->getValue(); } else { $custom = null; } // set data $this->data['keywords'] = $keywords; $this->data['keywords_overwrite'] = $this->frm->getField('meta_keywords_overwrite')->isChecked() ? 'Y' : 'N'; $this->data['description'] = $description; $this->data['description_overwrite'] = $this->frm->getField('meta_description_overwrite')->isChecked() ? 'Y' : 'N'; $this->data['title'] = $title; $this->data['title_overwrite'] = $this->frm->getField('page_title_overwrite')->isChecked() ? 'Y' : 'N'; $this->data['url'] = $URL; $this->data['url_overwrite'] = $this->frm->getField('url_overwrite')->isChecked() ? 'Y' : 'N'; $this->data['custom'] = $custom; if ($this->frm->getField('seo_index')->getValue() == 'none') { unset($this->data['data']['seo_index']); } else { $this->data['data']['seo_index'] = $this->frm->getField('seo_index')->getValue(); } if ($this->frm->getField('seo_follow')->getValue() == 'none') { unset($this->data['data']['seo_follow']); } else { $this->data['data']['seo_follow'] = $this->frm->getField('seo_follow')->getValue(); } } }
/** * Insert a page * * @return void * @param array $revision An array with the revision data. * @param array[optional] $meta The meta-data. * @param array[optional] $block The blocks. */ protected function insertPage(array $revision, array $meta = null, array $block = null) { // redefine $revision = (array) $revision; $meta = (array) $meta; // deactive previous revisions if (isset($revision['id']) && isset($revision['language'])) { $this->getDB()->update('pages', array('status' => 'archive'), 'id = ? AND language = ?', array($revision['id'], $revision['language'])); } // build revision if (!isset($revision['language'])) { throw new SpoonException('language is required for installing pages'); } if (!isset($revision['title'])) { throw new SpoonException('title is required for installing pages'); } if (!isset($revision['id'])) { $revision['id'] = (int) $this->getDB()->getVar('SELECT MAX(id) + 1 FROM pages WHERE language = ?', array($revision['language'])); } if (!$revision['id']) { $revision['id'] = 1; } if (!isset($revision['user_id'])) { $revision['user_id'] = $this->getDefaultUserID(); } if (!isset($revision['template_id'])) { $revision['template_id'] = $this->getDB()->getVar('SELECT id FROM pages_templates WHERE theme = ? ORDER BY path = ? DESC, id ASC', array($this->getSetting('core', 'theme'), 'core/layout/templates/default.tpl')); } if (!isset($revision['type'])) { $revision['type'] = 'page'; } if (!isset($revision['parent_id'])) { $revision['parent_id'] = $revision['type'] == 'page' ? 1 : 0; } if (!isset($revision['navigation_title'])) { $revision['navigation_title'] = $revision['title']; } if (!isset($revision['navigation_title_overwrite'])) { $revision['navigation_title_overwrite'] = 'N'; } if (!isset($revision['hidden'])) { $revision['hidden'] = 'N'; } if (!isset($revision['status'])) { $revision['status'] = 'active'; } if (!isset($revision['publish_on'])) { $revision['publish_on'] = gmdate('Y-m-d H:i:s'); } if (!isset($revision['created_on'])) { $revision['created_on'] = gmdate('Y-m-d H:i:s'); } if (!isset($revision['edited_on'])) { $revision['edited_on'] = gmdate('Y-m-d H:i:s'); } if (!isset($revision['data'])) { $revision['data'] = null; } if (!isset($revision['allow_move'])) { $revision['allow_move'] = 'Y'; } if (!isset($revision['allow_children'])) { $revision['allow_children'] = 'Y'; } if (!isset($revision['allow_edit'])) { $revision['allow_edit'] = 'Y'; } if (!isset($revision['allow_delete'])) { $revision['allow_delete'] = 'Y'; } if (!isset($revision['sequence'])) { $revision['sequence'] = (int) $this->getDB()->getVar('SELECT MAX(sequence) + 1 FROM pages WHERE language = ? AND parent_id = ? AND type = ?', array($revision['language'], $revision['parent_id'], $revision['type'])); } if (!isset($revision['extra_ids'])) { $revision['extra_ids'] = null; } if (!isset($revision['has_extra'])) { $revision['has_extra'] = $revision['extra_ids'] ? 'Y' : 'N'; } // meta needs to be inserted if (!isset($revision['meta_id'])) { // build meta if (!isset($meta['keywords'])) { $meta['keywords'] = $revision['title']; } if (!isset($meta['keywords_overwrite'])) { $meta['keywords_overwrite'] = false; } if (!isset($meta['description'])) { $meta['description'] = $revision['title']; } if (!isset($meta['description_overwrite'])) { $meta['description_overwrite'] = false; } if (!isset($meta['title'])) { $meta['title'] = $revision['title']; } if (!isset($meta['title_overwrite'])) { $meta['title_overwrite'] = false; } if (!isset($meta['url'])) { $meta['url'] = SpoonFilter::urlise($revision['title']); } if (!isset($meta['url_overwrite'])) { $meta['url_overwrite'] = false; } if (!isset($meta['custom'])) { $meta['custom'] = null; } if (!isset($meta['data'])) { $meta['data'] = null; } // insert meta $revision['meta_id'] = $this->insertMeta($meta['keywords'], $meta['description'], $meta['title'], $meta['url'], $meta['keywords_overwrite'], $meta['description_overwrite'], $meta['title_overwrite'], $meta['url_overwrite'], $meta['custom'], $meta['data']); } // insert page $revision['revision_id'] = $this->getDB()->insert('pages', $revision); // get number of blocks to insert $numBlocks = $this->getDB()->getVar('SELECT MAX(num_blocks) FROM pages_templates WHERE theme = ? AND active = ?', array($this->getSetting('core', 'theme'), 'Y')); // get arguments (this function has a variable length argument list, to allow multiple blocks to be added) $blocks = array(); // loop blocks for ($i = 0; $i < $numBlocks; $i++) { // get block $block = @func_get_arg($i + 2); if ($block === false) { $block = array(); } else { $block = (array) $block; } // build block if (!isset($block['id'])) { $block['id'] = $i; } if (!isset($block['revision_id'])) { $block['revision_id'] = $revision['revision_id']; } if (!isset($block['status'])) { $block['status'] = 'active'; } if (!isset($block['created_on'])) { $block['created_on'] = gmdate('Y-m-d H:i:s'); } if (!isset($block['edited_on'])) { $block['edited_on'] = gmdate('Y-m-d H:i:s'); } if (!isset($block['extra_id'])) { $block['extra_id'] = null; } else { $revision['extra_ids'] = trim($revision['extra_ids'] . ',' . $block['extra_id'], ','); } if (!isset($block['html'])) { $block['html'] = ''; } elseif (SpoonFile::exists($block['html'])) { $block['html'] = SpoonFile::getContent($block['html']); } // insert block $this->getDB()->insert('pages_blocks', $block); } // blocks added if ($revision['extra_ids'] && $revision['has_extra'] == 'N') { // update page $revision['has_extra'] = 'Y'; $this->getDB()->update('pages', $revision, 'revision_id = ?', array($revision['revision_id'])); } // return page id return $revision['id']; }
/** * Retrieve a unique URL for a profile based on the display name. * * @param string $displayName The display name to base on. * @param int[optional] $id The id of the profile to ignore. * @return string */ public static function getUrl($displayName, $id = null) { // decode specialchars $displayName = SpoonFilter::htmlspecialcharsDecode((string) $displayName); // urlise $url = (string) SpoonFilter::urlise($displayName); // get db $db = FrontendModel::getDB(); // new item if ($id === null) { // get number of profiles with this URL $number = (int) $db->getVar('SELECT COUNT(p.id) FROM profiles AS p WHERE p.url = ?', (string) $url); // already exists if ($number != 0) { // add number $url = FrontendModel::addNumber($url); // try again return self::getURL($url); } } else { // get number of profiles with this URL $number = (int) $db->getVar('SELECT COUNT(p.id) FROM profiles AS p WHERE p.url = ? AND p.id != ?', array((string) $url, (int) $id)); // already exists if ($number != 0) { // add number $url = FrontendModel::addNumber($url); // try again return self::getURL($url, $id); } } return $url; }
/** * Insert a meta item * * @param string $keywords The keyword of the item. * @param string $description A description of the item. * @param string $title The page title for the item. * @param string $url The unique URL. * @param bool[optional] $keywordsOverwrite Should the keywords be overwritten? * @param bool[optional] $descriptionOverwrite Should the descriptions be overwritten? * @param bool[optional] $titleOverwrite Should the pagetitle be overwritten? * @param bool[optional] $urlOverwrite Should the URL be overwritten? * @param string[optional] $custom Any custom meta-data. * @param array[optional] $data Any custom meta-data. * @return int */ protected function insertMeta($keywords, $description, $title, $url, $keywordsOverwrite = false, $descriptionOverwrite = false, $titleOverwrite = false, $urlOverwrite = false, $custom = null, $data = null) { $item = array('keywords' => (string) $keywords, 'keywords_overwrite' => $keywordsOverwrite && $keywordsOverwrite !== 'N' ? 'Y' : 'N', 'description' => (string) $description, 'description_overwrite' => $descriptionOverwrite && $descriptionOverwrite !== 'N' ? 'Y' : 'N', 'title' => (string) $title, 'title_overwrite' => $titleOverwrite && $titleOverwrite !== 'N' ? 'Y' : 'N', 'url' => SpoonFilter::urlise((string) $url, SPOON_CHARSET), 'url_overwrite' => $urlOverwrite && $urlOverwrite !== 'N' ? 'Y' : 'N', 'custom' => !is_null($custom) ? (string) $custom : null, 'data' => !is_null($data) ? serialize($data) : null); return (int) $this->getDB()->insert('meta', $item); }
/** * Retrieve the unique URL for a category * * @param string $url * @param int[optional] $id The id of the category to ignore. * @return string */ public static function getURLForCategory($url, $id = null) { $url = SpoonFilter::urlise((string) $url); $db = BackendModel::getDB(); // new category if ($id === null) { if ((bool) $db->getVar('SELECT 1 FROM faq_categories AS i INNER JOIN meta AS m ON i.meta_id = m.id WHERE i.language = ? AND m.url = ? LIMIT 1', array(BL::getWorkingLanguage(), $url))) { $url = BackendModel::addNumber($url); return self::getURLForCategory($url); } } else { if ((bool) $db->getVar('SELECT 1 FROM faq_categories AS i INNER JOIN meta AS m ON i.meta_id = m.id WHERE i.language = ? AND m.url = ? AND i.id != ? LIMIT 1', array(BL::getWorkingLanguage(), $url, $id))) { $url = BackendModel::addNumber($url); return self::getURLForCategory($url, $id); } } return $url; }
/** * Update a locale item. * * @param array $item The new data. */ public static function update(array $item) { // actions should be urlized if ($item['type'] == 'act' && urldecode($item['value']) != $item['value']) { $item['value'] = SpoonFilter::urlise($item['value']); } // update category $updated = BackendModel::getDB(true)->update('locale', $item, 'id = ?', array($item['id'])); // rebuild the cache self::buildCache($item['language'], $item['application']); return $updated; }
/** * Validate the form */ private function validateForm() { if ($this->frm->isSubmitted()) { $this->frm->cleanupFields(); // redefine fields $txtName = $this->frm->getField('name'); $txtValue = $this->frm->getField('value'); // name checks if ($txtName->isFilled(BL::err('FieldIsRequired'))) { // allowed regex (a-z and 0-9) if ($txtName->isValidAgainstRegexp('|^([a-z0-9])+$|i', BL::err('InvalidName'))) { // first letter does not seem to be a capital one if (!in_array(substr($txtName->getValue(), 0, 1), range('A', 'Z'))) { $txtName->setError(BL::err('InvalidName')); } else { // this name already exists in this language if (BackendLocaleModel::existsByName($txtName->getValue(), $this->frm->getField('type')->getValue(), $this->frm->getField('module')->getValue(), $this->frm->getField('language')->getValue(), $this->frm->getField('application')->getValue())) { $txtName->setError(BL::err('AlreadyExists')); } } } } // value checks if ($txtValue->isFilled(BL::err('FieldIsRequired'))) { // in case this is a 'act' type, there are special rules concerning possible values if ($this->frm->getField('type')->getValue() == 'act') { if (urlencode($txtValue->getValue()) != SpoonFilter::urlise($txtValue->getValue())) { $txtValue->addError(BL::err('InvalidValue')); } } } // module should be 'core' for any other application than backend if ($this->frm->getField('application')->getValue() != 'backend' && $this->frm->getField('module')->getValue() != 'core') { $this->frm->getField('module')->setError(BL::err('ModuleHasToBeCore')); } if ($this->frm->isCorrect()) { // build item $item['user_id'] = BackendAuthentication::getUser()->getUserId(); $item['language'] = $this->frm->getField('language')->getValue(); $item['application'] = $this->frm->getField('application')->getValue(); $item['module'] = $this->frm->getField('module')->getValue(); $item['type'] = $this->frm->getField('type')->getValue(); $item['name'] = $this->frm->getField('name')->getValue(); $item['value'] = $this->frm->getField('value')->getValue(); $item['edited_on'] = BackendModel::getUTCDate(); // update item $item['id'] = BackendLocaleModel::insert($item); // trigger event BackendModel::triggerEvent($this->getModule(), 'after_add', array('item' => $item)); // everything is saved, so redirect to the overview $this->redirect(BackendModel::createURLForAction('index', null, null, null) . '&report=added&var=' . urlencode($item['name']) . '&highlight=row-' . $item['id'] . $this->filterQuery); } } }
/** * Set the author. * * @param string $author The author to use. */ public function setAuthor($author) { // remove special chars $author = (string) \SpoonFilter::htmlspecialcharsDecode($author); // add fake-emailaddress if (!\SpoonFilter::isEmail($author)) { $author = CommonUri::getUrl($author) . '@example.com (' . $author . ')'; } // add fake email address if (!\SpoonFilter::isEmail($author)) { $author = \SpoonFilter::urlise($author) . '@example.com (' . $author . ')'; } // set author parent::setAuthor($author); }
public function testUrlise() { $this->assertEquals(urlencode('géén-bananen'), SpoonFilter::urlise('géén bananen')); $this->assertEquals('tom-jerry', SpoonFilter::urlise('Tom & Jerry')); $this->assertEquals(urlencode('¬'), SpoonFilter::urlise('¬')); }
/** * Validate the form */ private function validateForm() { // is the form submitted? if ($this->frm->isSubmitted()) { // cleanup the submitted fields, ignore fields that were added by hackers $this->frm->cleanupFields(); // validate fields $this->frm->getField('name')->isFilled(BL::err('NameIsRequired')); // no errors? if ($this->frm->isCorrect()) { // build tag $item['id'] = $this->id; $item['tag'] = $this->frm->getField('name')->getValue(); $item['url'] = BackendTagsModel::getURL(SpoonFilter::urlise(SpoonFilter::htmlspecialcharsDecode($item['tag'])), $this->id); // update the item BackendTagsModel::update($item); // trigger event BackendModel::triggerEvent($this->getModule(), 'after_edit', array('item' => $item)); // everything is saved, so redirect to the overview $this->redirect(BackendModel::createURLForAction('index') . '&report=edited&var=' . urlencode($item['tag']) . '&highlight=row-' . $item['id']); } } }