1007225e5Sgerardnico<?php 2007225e5Sgerardnico/** 3007225e5Sgerardnico * Front Matter implementation to add metadata 4007225e5Sgerardnico * 5007225e5Sgerardnico * 6007225e5Sgerardnico * that enhance the metadata dokuwiki system 7007225e5Sgerardnico * https://www.dokuwiki.org/metadata 8007225e5Sgerardnico * that use the Dublin Core Standard 9007225e5Sgerardnico * http://dublincore.org/ 10007225e5Sgerardnico * by adding the front matter markup specification 11007225e5Sgerardnico * https://gerardnico.com/markup/front-matter 12007225e5Sgerardnico * 13007225e5Sgerardnico * Inspiration 14007225e5Sgerardnico * https://github.com/dokufreaks/plugin-meta/blob/master/syntax.php 15007225e5Sgerardnico * https://www.dokuwiki.org/plugin:semantic 16007225e5Sgerardnico * 17007225e5Sgerardnico * See also structured plugin 18007225e5Sgerardnico * https://www.dokuwiki.org/plugin:data 19007225e5Sgerardnico * https://www.dokuwiki.org/plugin:struct 20007225e5Sgerardnico * 21007225e5Sgerardnico */ 22007225e5Sgerardnico 2337748cd8SNickeauuse ComboStrap\Analytics; 2437748cd8SNickeauuse ComboStrap\CacheManager; 2537748cd8SNickeauuse ComboStrap\Iso8601Date; 26007225e5Sgerardnicouse ComboStrap\LogUtility; 2737748cd8SNickeauuse ComboStrap\MediaLink; 2871f916b9Sgerardnicouse ComboStrap\Page; 29a6bf47aaSNickeauuse ComboStrap\PluginUtility; 3037748cd8SNickeauuse ComboStrap\Publication; 31007225e5Sgerardnico 3237748cd8SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 33007225e5Sgerardnico 34007225e5Sgerardnico 35007225e5Sgerardnico/** 36007225e5Sgerardnico * All DokuWiki plugins to extend the parser/rendering mechanism 37007225e5Sgerardnico * need to inherit from this class 38d5303bc5Sgerardnico * 39d5303bc5Sgerardnico * For a list of meta, see also https://ghost.org/docs/publishing/#api-data 40007225e5Sgerardnico */ 41007225e5Sgerardnicoclass syntax_plugin_combo_frontmatter extends DokuWiki_Syntax_Plugin 42007225e5Sgerardnico{ 43007225e5Sgerardnico const PARSING_STATE_EMPTY = "empty"; 44007225e5Sgerardnico const PARSING_STATE_ERROR = "error"; 45007225e5Sgerardnico const PARSING_STATE_SUCCESSFUL = "successful"; 465f891b7eSNickeau const STATUS = "status"; 475f891b7eSNickeau const CANONICAL = "frontmatter"; 4821913ab3SNickeau const CONF_ENABLE_SECTION_EDITING = 'enableFrontMatterSectionEditing'; 49007225e5Sgerardnico 50007225e5Sgerardnico /** 5137748cd8SNickeau * Used in the move plugin 5237748cd8SNickeau * !!! The two last word of the plugin class !!! 5337748cd8SNickeau */ 5437748cd8SNickeau const COMPONENT = 'combo_' . self::CANONICAL; 5537748cd8SNickeau const START_TAG = '---json'; 5637748cd8SNickeau const END_TAG = '---'; 5737748cd8SNickeau const METADATA_IMAGE_CANONICAL = "metadata:image"; 5837748cd8SNickeau 5937748cd8SNickeau /** 6037748cd8SNickeau * @param $match 6137748cd8SNickeau * @return array|mixed - null if decodage problem, empty array if no json or an associative array 6237748cd8SNickeau */ 6337748cd8SNickeau public static function FrontMatterMatchToAssociativeArray($match) 6437748cd8SNickeau { 6537748cd8SNickeau // strip 6637748cd8SNickeau // from start `---json` + eol = 8 6737748cd8SNickeau // from end `---` + eol = 4 6837748cd8SNickeau $jsonString = substr($match, 7, -3); 6937748cd8SNickeau 7037748cd8SNickeau // Empty front matter 7137748cd8SNickeau if (trim($jsonString) == "") { 7237748cd8SNickeau self::deleteKnownMetaThatAreNoMorePresent(); 7337748cd8SNickeau return []; 7437748cd8SNickeau } 7537748cd8SNickeau 7637748cd8SNickeau // Otherwise you get an object ie $arrayFormat-> syntax 7737748cd8SNickeau $arrayFormat = true; 7837748cd8SNickeau return json_decode($jsonString, $arrayFormat); 7937748cd8SNickeau } 8037748cd8SNickeau 8137748cd8SNickeau /** 82007225e5Sgerardnico * Syntax Type. 83007225e5Sgerardnico * 84007225e5Sgerardnico * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 85007225e5Sgerardnico * @see https://www.dokuwiki.org/devel:syntax_plugins#syntax_types 86007225e5Sgerardnico * 87007225e5Sgerardnico * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php 88007225e5Sgerardnico * 89007225e5Sgerardnico * baseonly - run only in the base 90007225e5Sgerardnico */ 91007225e5Sgerardnico function getType() 92007225e5Sgerardnico { 93007225e5Sgerardnico return 'baseonly'; 94007225e5Sgerardnico } 95007225e5Sgerardnico 96531e725cSNickeau public function getPType() 97531e725cSNickeau { 9885e82846SNickeau /** 9985e82846SNickeau * This element create a section 10085e82846SNickeau * element that is a div 10185e82846SNickeau * that should not be in paragraph 10285e82846SNickeau * 10385e82846SNickeau * We make it a block 10485e82846SNickeau */ 10585e82846SNickeau return "block"; 106531e725cSNickeau } 107531e725cSNickeau 108531e725cSNickeau 109007225e5Sgerardnico /** 110007225e5Sgerardnico * @see Doku_Parser_Mode::getSort() 111007225e5Sgerardnico * Higher number than the teaser-columns 112007225e5Sgerardnico * because the mode with the lowest sort number will win out 113007225e5Sgerardnico */ 114007225e5Sgerardnico function getSort() 115007225e5Sgerardnico { 116007225e5Sgerardnico return 99; 117007225e5Sgerardnico } 118007225e5Sgerardnico 119007225e5Sgerardnico /** 120007225e5Sgerardnico * Create a pattern that will called this plugin 121007225e5Sgerardnico * 122007225e5Sgerardnico * @param string $mode 123007225e5Sgerardnico * @see Doku_Parser_Mode::connectTo() 124007225e5Sgerardnico */ 125007225e5Sgerardnico function connectTo($mode) 126007225e5Sgerardnico { 127007225e5Sgerardnico if ($mode == "base") { 128007225e5Sgerardnico // only from the top 12937748cd8SNickeau $this->Lexer->addSpecialPattern(self::START_TAG . '.*?' . self::END_TAG, $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 130007225e5Sgerardnico } 131007225e5Sgerardnico } 132007225e5Sgerardnico 133007225e5Sgerardnico /** 134007225e5Sgerardnico * 135007225e5Sgerardnico * The handle function goal is to parse the matched syntax through the pattern function 136007225e5Sgerardnico * and to return the result for use in the renderer 137007225e5Sgerardnico * This result is always cached until the page is modified. 138007225e5Sgerardnico * @param string $match 139007225e5Sgerardnico * @param int $state 140007225e5Sgerardnico * @param int $pos 141007225e5Sgerardnico * @param Doku_Handler $handler 142007225e5Sgerardnico * @return array|bool 143007225e5Sgerardnico * @see DokuWiki_Syntax_Plugin::handle() 144007225e5Sgerardnico * 145007225e5Sgerardnico */ 146007225e5Sgerardnico function handle($match, $state, $pos, Doku_Handler $handler) 147007225e5Sgerardnico { 148007225e5Sgerardnico 149007225e5Sgerardnico if ($state == DOKU_LEXER_SPECIAL) { 150007225e5Sgerardnico 151007225e5Sgerardnico 15237748cd8SNickeau $jsonArray = self::FrontMatterMatchToAssociativeArray($match); 153007225e5Sgerardnico 154007225e5Sgerardnico 155a6bf47aaSNickeau $result = []; 156007225e5Sgerardnico // Decodage problem 157531e725cSNickeau if ($jsonArray == null) { 15837748cd8SNickeau 159a6bf47aaSNickeau $result[self::STATUS] = self::PARSING_STATE_ERROR; 160a6bf47aaSNickeau $result[PluginUtility::PAYLOAD] = $match; 16137748cd8SNickeau 162a6bf47aaSNickeau } else { 16337748cd8SNickeau 16437748cd8SNickeau if (sizeof($jsonArray) === 0) { 16537748cd8SNickeau return array(self::STATUS => self::PARSING_STATE_EMPTY); 16637748cd8SNickeau } 16737748cd8SNickeau 1685f891b7eSNickeau $result[self::STATUS] = self::PARSING_STATE_SUCCESSFUL; 16937748cd8SNickeau /** 17037748cd8SNickeau * Published is an alias for date published 17137748cd8SNickeau */ 17237748cd8SNickeau if (isset($jsonArray[Publication::OLD_META_KEY])) { 17337748cd8SNickeau $jsonArray[Publication::DATE_PUBLISHED] = $jsonArray[Publication::OLD_META_KEY]; 17437748cd8SNickeau unset($jsonArray[Publication::OLD_META_KEY]); 17537748cd8SNickeau } 17637748cd8SNickeau /** 17737748cd8SNickeau * Add the time part if not present 17837748cd8SNickeau */ 17937748cd8SNickeau if (isset($jsonArray[Publication::DATE_PUBLISHED])) { 180*1fa8c418SNickeau $dateAsString = $jsonArray[Publication::DATE_PUBLISHED]; 181*1fa8c418SNickeau $dateObject = Iso8601Date::create($dateAsString); 182*1fa8c418SNickeau if (!$dateObject->isValidDateEntry()) { 183*1fa8c418SNickeau LogUtility::msg("The published date ($dateAsString) is not a valid date supported.", LogUtility::LVL_MSG_ERROR, Iso8601Date::CANONICAL); 18437748cd8SNickeau unset($jsonArray[Publication::DATE_PUBLISHED]); 18537748cd8SNickeau } else { 186*1fa8c418SNickeau $jsonArray[Publication::DATE_PUBLISHED] = "$dateObject"; 187*1fa8c418SNickeau } 18837748cd8SNickeau } 18937748cd8SNickeau 190*1fa8c418SNickeau if (isset($jsonArray[Analytics::DATE_START])) { 191*1fa8c418SNickeau $dateAsString = $jsonArray[Analytics::DATE_START]; 192*1fa8c418SNickeau $dateObject = Iso8601Date::create($dateAsString); 193*1fa8c418SNickeau if (!$dateObject->isValidDateEntry()) { 194*1fa8c418SNickeau LogUtility::msg("The start date ($dateAsString) is not a valid date supported.", LogUtility::LVL_MSG_ERROR, Iso8601Date::CANONICAL); 195*1fa8c418SNickeau unset($jsonArray[Analytics::DATE_START]); 196*1fa8c418SNickeau } else { 197*1fa8c418SNickeau $jsonArray[Analytics::DATE_START] = "$dateObject"; 19837748cd8SNickeau } 199*1fa8c418SNickeau } 200*1fa8c418SNickeau 201*1fa8c418SNickeau if (isset($jsonArray[Analytics::DATE_END])) { 202*1fa8c418SNickeau $dateAsString = $jsonArray[Analytics::DATE_END]; 203*1fa8c418SNickeau $dateObject = Iso8601Date::create($dateAsString); 204*1fa8c418SNickeau if (!$dateObject->isValidDateEntry()) { 205*1fa8c418SNickeau LogUtility::msg("The end date ($dateAsString) is not a valid date supported.", LogUtility::LVL_MSG_ERROR, Iso8601Date::CANONICAL); 206*1fa8c418SNickeau unset($jsonArray[Analytics::DATE_END]); 207*1fa8c418SNickeau } else { 208*1fa8c418SNickeau $jsonArray[Analytics::DATE_END] = "$dateObject"; 209*1fa8c418SNickeau } 210*1fa8c418SNickeau } 211*1fa8c418SNickeau 212a6bf47aaSNickeau $result[PluginUtility::ATTRIBUTES] = $jsonArray; 213a6bf47aaSNickeau } 214531e725cSNickeau 215531e725cSNickeau /** 216531e725cSNickeau * End position is the length of the match + 1 for the newline 217531e725cSNickeau */ 218531e725cSNickeau $newLine = 1; 219531e725cSNickeau $endPosition = $pos + strlen($match) + $newLine; 220531e725cSNickeau $result[PluginUtility::POSITION] = [$pos, $endPosition]; 221007225e5Sgerardnico 222007225e5Sgerardnico return $result; 223007225e5Sgerardnico } 224007225e5Sgerardnico 225007225e5Sgerardnico return array(); 226007225e5Sgerardnico } 227007225e5Sgerardnico 228007225e5Sgerardnico /** 229007225e5Sgerardnico * Render the output 230007225e5Sgerardnico * @param string $format 231007225e5Sgerardnico * @param Doku_Renderer $renderer 232007225e5Sgerardnico * @param array $data - what the function handle() return'ed 233007225e5Sgerardnico * @return boolean - rendered correctly? (however, returned value is not used at the moment) 234007225e5Sgerardnico * @see DokuWiki_Syntax_Plugin::render() 235007225e5Sgerardnico * 236007225e5Sgerardnico * 237007225e5Sgerardnico */ 238007225e5Sgerardnico function render($format, Doku_Renderer $renderer, $data) 239007225e5Sgerardnico { 240007225e5Sgerardnico 241007225e5Sgerardnico switch ($format) { 242007225e5Sgerardnico case 'xhtml': 243007225e5Sgerardnico global $ID; 244007225e5Sgerardnico /** @var Doku_Renderer_xhtml $renderer */ 24521913ab3SNickeau 2465f891b7eSNickeau $state = $data[self::STATUS]; 247007225e5Sgerardnico if ($state == self::PARSING_STATE_ERROR) { 2485f891b7eSNickeau $json = $data[PluginUtility::PAYLOAD]; 2495f891b7eSNickeau LogUtility::msg("Front Matter: The json object for the page ($ID) is not valid. See the errors it by clicking on <a href=\"https://jsonformatter.curiousconcept.com/?data=" . urlencode($json) . "\">this link</a>.", LogUtility::LVL_MSG_ERROR); 250007225e5Sgerardnico } 25121913ab3SNickeau 25221913ab3SNickeau /** 25321913ab3SNickeau * Section 25421913ab3SNickeau */ 25521913ab3SNickeau list($startPosition, $endPosition) = $data[PluginUtility::POSITION]; 25621913ab3SNickeau if (PluginUtility::getConfValue(self::CONF_ENABLE_SECTION_EDITING, 1)) { 25721913ab3SNickeau $position = $startPosition; 25821913ab3SNickeau $name = self::CANONICAL; 25921913ab3SNickeau PluginUtility::startSection($renderer, $position, $name); 26021913ab3SNickeau $renderer->finishSectionEdit($endPosition); 26121913ab3SNickeau } 262007225e5Sgerardnico break; 263531e725cSNickeau case renderer_plugin_combo_analytics::RENDERER_FORMAT: 264a6bf47aaSNickeau 265a6bf47aaSNickeau if ($data[self::STATUS] != self::PARSING_STATE_SUCCESSFUL) { 266a6bf47aaSNickeau return false; 267a6bf47aaSNickeau } 268a6bf47aaSNickeau 26937748cd8SNickeau $notModifiableMeta = [ 27037748cd8SNickeau Analytics::PATH, 27137748cd8SNickeau Analytics::DATE_CREATED, 27237748cd8SNickeau Analytics::DATE_MODIFIED 27337748cd8SNickeau ]; 27437748cd8SNickeau 275007225e5Sgerardnico /** @var renderer_plugin_combo_analytics $renderer */ 276a6bf47aaSNickeau $jsonArray = $data[PluginUtility::ATTRIBUTES]; 27737748cd8SNickeau foreach ($jsonArray as $key => $value) { 27837748cd8SNickeau if (!in_array($key, $notModifiableMeta)) { 27937748cd8SNickeau 28037748cd8SNickeau $renderer->setMeta($key, $value); 28137748cd8SNickeau if ($key === Page::IMAGE_META_PROPERTY) { 28237748cd8SNickeau $this->updateImageStatistics($value, $renderer); 283007225e5Sgerardnico } 28437748cd8SNickeau 28537748cd8SNickeau } else { 28637748cd8SNickeau LogUtility::msg("The metadata ($key) cannot be set.", LogUtility::LVL_MSG_ERROR, self::CANONICAL); 287007225e5Sgerardnico } 2889b9e6d1fSgerardnico } 289007225e5Sgerardnico break; 29037748cd8SNickeau 291a6bf47aaSNickeau case "metadata": 292a6bf47aaSNickeau 29337748cd8SNickeau /** @var Doku_Renderer_metadata $renderer */ 294a6bf47aaSNickeau if ($data[self::STATUS] != self::PARSING_STATE_SUCCESSFUL) { 295a6bf47aaSNickeau return false; 296a6bf47aaSNickeau } 297a6bf47aaSNickeau 298a6bf47aaSNickeau global $ID; 299a6bf47aaSNickeau $jsonArray = $data[PluginUtility::ATTRIBUTES]; 300a6bf47aaSNickeau 301a6bf47aaSNickeau 302a6bf47aaSNickeau $notModifiableMeta = [ 303a6bf47aaSNickeau "date", 304a6bf47aaSNickeau "user", 305a6bf47aaSNickeau "last_change", 306a6bf47aaSNickeau "creator", 307a6bf47aaSNickeau "contributor" 308a6bf47aaSNickeau ]; 309a6bf47aaSNickeau 310a6bf47aaSNickeau foreach ($jsonArray as $key => $value) { 311a6bf47aaSNickeau 312a6bf47aaSNickeau $lowerCaseKey = trim(strtolower($key)); 313a6bf47aaSNickeau 314a6bf47aaSNickeau // Not modifiable metadata 315a6bf47aaSNickeau if (in_array($lowerCaseKey, $notModifiableMeta)) { 316a6bf47aaSNickeau LogUtility::msg("Front Matter: The metadata ($lowerCaseKey) is a protected metadata and cannot be modified", LogUtility::LVL_MSG_WARNING); 317a6bf47aaSNickeau continue; 318a6bf47aaSNickeau } 319a6bf47aaSNickeau 320a6bf47aaSNickeau switch ($lowerCaseKey) { 321a6bf47aaSNickeau 322a6bf47aaSNickeau case Page::DESCRIPTION_PROPERTY: 323a6bf47aaSNickeau /** 324a6bf47aaSNickeau * Overwrite also the actual description 325a6bf47aaSNickeau */ 326a6bf47aaSNickeau p_set_metadata($ID, array(Page::DESCRIPTION_PROPERTY => array( 327a6bf47aaSNickeau "abstract" => $value, 328a6bf47aaSNickeau "origin" => syntax_plugin_combo_frontmatter::CANONICAL 329a6bf47aaSNickeau ))); 330a6bf47aaSNickeau /** 331a6bf47aaSNickeau * Continue because 332a6bf47aaSNickeau * the description value was already stored 333a6bf47aaSNickeau * We don't want to override it 334a6bf47aaSNickeau * And continue 2 because continue == break in a switch 335a6bf47aaSNickeau */ 336a6bf47aaSNickeau continue 2; 337a6bf47aaSNickeau 338a6bf47aaSNickeau 339a6bf47aaSNickeau // Canonical should be lowercase 340a6bf47aaSNickeau case Page::CANONICAL_PROPERTY: 341a6bf47aaSNickeau $value = strtolower($value); 342a6bf47aaSNickeau break; 343a6bf47aaSNickeau 34437748cd8SNickeau case Page::IMAGE_META_PROPERTY: 34537748cd8SNickeau 34637748cd8SNickeau $imageValues = []; 34737748cd8SNickeau $this->aggregateImageValues($imageValues, $value); 34837748cd8SNickeau foreach ($imageValues as $imageValue) { 34937748cd8SNickeau $media = MediaLink::createFromRenderMatch($imageValue); 35037748cd8SNickeau $attributes = $media->toCallStackArray(); 35137748cd8SNickeau syntax_plugin_combo_media::registerImageMeta($attributes, $renderer); 35237748cd8SNickeau } 35337748cd8SNickeau break; 35437748cd8SNickeau 355a6bf47aaSNickeau } 356a6bf47aaSNickeau // Set the value persistently 357a6bf47aaSNickeau p_set_metadata($ID, array($lowerCaseKey => $value)); 358a6bf47aaSNickeau 359a6bf47aaSNickeau } 360a6bf47aaSNickeau 361a6bf47aaSNickeau $this->deleteKnownMetaThatAreNoMorePresent($jsonArray); 362a6bf47aaSNickeau 363a6bf47aaSNickeau break; 364007225e5Sgerardnico 365007225e5Sgerardnico } 366007225e5Sgerardnico return true; 367007225e5Sgerardnico } 368007225e5Sgerardnico 369007225e5Sgerardnico /** 370007225e5Sgerardnico * 371007225e5Sgerardnico * @param array $json - The Json 372007225e5Sgerardnico * Delete the controlled meta that are no more present if they exists 373007225e5Sgerardnico * @return bool 374007225e5Sgerardnico */ 37537748cd8SNickeau static public 376a6bf47aaSNickeau function deleteKnownMetaThatAreNoMorePresent(array $json = array()) 377007225e5Sgerardnico { 378007225e5Sgerardnico global $ID; 379007225e5Sgerardnico 380007225e5Sgerardnico /** 381007225e5Sgerardnico * The managed meta with the exception of 382007225e5Sgerardnico * the {@link action_plugin_combo_metadescription::DESCRIPTION_META_KEY description} 383007225e5Sgerardnico * because it's already managed by dokuwiki in description['abstract'] 384007225e5Sgerardnico */ 385007225e5Sgerardnico $managedMeta = [ 38671f916b9Sgerardnico Page::CANONICAL_PROPERTY, 38737748cd8SNickeau Page::TYPE_META_PROPERTY, 38837748cd8SNickeau Page::IMAGE_META_PROPERTY, 38937748cd8SNickeau Page::COUNTRY_META_PROPERTY, 39037748cd8SNickeau Page::LANG_META_PROPERTY, 39137748cd8SNickeau Analytics::TITLE, 39237748cd8SNickeau syntax_plugin_combo_disqus::META_DISQUS_IDENTIFIER, 39337748cd8SNickeau Publication::OLD_META_KEY, 39437748cd8SNickeau Publication::DATE_PUBLISHED, 39537748cd8SNickeau Analytics::NAME, 39637748cd8SNickeau CacheManager::DATE_CACHE_EXPIRATION_META_KEY, 39737748cd8SNickeau action_plugin_combo_metagoogle::JSON_LD_META_PROPERTY, 39837748cd8SNickeau 399007225e5Sgerardnico ]; 400007225e5Sgerardnico $meta = p_read_metadata($ID); 401007225e5Sgerardnico foreach ($managedMeta as $metaKey) { 402007225e5Sgerardnico if (!array_key_exists($metaKey, $json)) { 403007225e5Sgerardnico if (isset($meta['persistent'][$metaKey])) { 404007225e5Sgerardnico unset($meta['persistent'][$metaKey]); 405007225e5Sgerardnico } 406007225e5Sgerardnico } 407007225e5Sgerardnico } 408007225e5Sgerardnico return p_save_metadata($ID, $meta); 409007225e5Sgerardnico } 410007225e5Sgerardnico 41137748cd8SNickeau private function updateImageStatistics($value, $renderer) 41237748cd8SNickeau { 41337748cd8SNickeau if(is_array($value)){ 41437748cd8SNickeau foreach($value as $subImage){ 41537748cd8SNickeau $this->updateImageStatistics($subImage, $renderer); 41637748cd8SNickeau } 41737748cd8SNickeau } else { 41837748cd8SNickeau $media = MediaLink::createFromRenderMatch($value); 41937748cd8SNickeau $attributes = $media->toCallStackArray(); 42037748cd8SNickeau syntax_plugin_combo_media::updateStatistics($attributes, $renderer); 42137748cd8SNickeau } 42237748cd8SNickeau } 42337748cd8SNickeau 42437748cd8SNickeau private function aggregateImageValues(array &$imageValues, $value) 42537748cd8SNickeau { 42637748cd8SNickeau if (is_array($value)) { 42737748cd8SNickeau foreach ($value as $subImageValue) { 42837748cd8SNickeau $this->aggregateImageValues($imageValues,$subImageValue); 42937748cd8SNickeau } 43037748cd8SNickeau } else { 43137748cd8SNickeau $imageValues[] = $value; 43237748cd8SNickeau } 43337748cd8SNickeau } 43437748cd8SNickeau 435007225e5Sgerardnico 436007225e5Sgerardnico} 437007225e5Sgerardnico 438