vendor/pimcore/pimcore/lib/Tool/Text.php line 64

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Tool;
  15. use Onnov\DetectEncoding\EncodingDetector;
  16. use Pimcore\Cache\RuntimeCache;
  17. use Pimcore\Model\Asset;
  18. use Pimcore\Model\DataObject\Concrete;
  19. use Pimcore\Model\Document;
  20. use Pimcore\Model\Element;
  21. class Text
  22. {
  23.     /**
  24.      * @param string $text
  25.      *
  26.      * @return string
  27.      */
  28.     public static function removeLineBreaks($text '')
  29.     {
  30.         $text str_replace(["\r\n""\n""\r""\t"], ' '$text);
  31.         $text preg_replace('#[ ]+#'' '$text);
  32.         return $text;
  33.     }
  34.     /**
  35.      * @param string|null $text
  36.      * @param array $params
  37.      *
  38.      * @return string|null
  39.      */
  40.     public static function wysiwygText($text$params = [])
  41.     {
  42.         if (empty($text)) {
  43.             return $text;
  44.         }
  45.         $matches self::getElementsTagsInWysiwyg($text);
  46.         if (count($matches[2]) > 0) {
  47.             for ($i 0$i count($matches[2]); $i++) {
  48.                 preg_match('/[0-9]+/'$matches[2][$i], $idMatches);
  49.                 preg_match('/asset|object|document/'$matches[3][$i], $typeMatches);
  50.                 $linkAttr null;
  51.                 $path null;
  52.                 $additionalAttributes = [];
  53.                 $id $idMatches[0];
  54.                 $type $typeMatches[0];
  55.                 $element Element\Service::getElementById($type$id);
  56.                 $oldTag $matches[0][$i];
  57.                 if ($element instanceof Element\ElementInterface) {
  58.                     if ($matches[1][$i] == 'a') {
  59.                         $linkAttr 'href';
  60.                         $path $element->getFullPath();
  61.                         if (($element instanceof Document || $element instanceof Concrete) && !$element->isPublished()) {
  62.                             $path null;
  63.                         } elseif ($element instanceof Document) {
  64.                             // get parameters
  65.                             preg_match('/href="([^"]+)*"/'$oldTag$oldHref);
  66.                             if ($oldHref[1] && (strpos($oldHref[1], '?') !== false || strpos($oldHref[1], '#') !== false)) {
  67.                                 $urlParts parse_url($oldHref[1]);
  68.                                 if (array_key_exists('query'$urlParts) && !empty($urlParts['query'])) {
  69.                                     $path .= '?' $urlParts['query'];
  70.                                 }
  71.                                 if (array_key_exists('fragment'$urlParts) && !empty($urlParts['fragment'])) {
  72.                                     $path .= '#' $urlParts['fragment'];
  73.                                 }
  74.                             }
  75.                         } elseif ($element instanceof Concrete) {
  76.                             if ($linkGenerator $element->getClass()->getLinkGenerator()) {
  77.                                 $path $linkGenerator->generate(
  78.                                     $element,
  79.                                     $params
  80.                                 );
  81.                             } else {
  82.                                 // no object path without link generator!
  83.                                 $path null;
  84.                             }
  85.                         }
  86.                     } elseif ($matches[1][$i] == 'img') {
  87.                         $linkAttr 'src';
  88.                         // only for images
  89.                         if (!$element instanceof Asset\Image) {
  90.                             continue;
  91.                         }
  92.                         $path $element->getFullPath();
  93.                         // resize image to the given attributes
  94.                         $config null;
  95.                         preg_match('/width="([^"]+)*"/'$oldTag$widthAttr);
  96.                         preg_match('/height="([^"]+)*"/'$oldTag$heightAttr);
  97.                         preg_match('/style="([^"]+)*"/'$oldTag$styleAttr);
  98.                         if ((isset($widthAttr[1]) && $widthAttr[1]) || (isset($heightAttr[1]) && $heightAttr[1])) {
  99.                             $config = [
  100.                                 'width' => (int)(isset($widthAttr[1]) ? $widthAttr[1] : null),
  101.                                 'height' => (int)(isset($heightAttr[1]) ? $heightAttr[1] : null),
  102.                             ];
  103.                         }
  104.                         if (isset($styleAttr[1]) && $styleAttr[1] && preg_match('/(width|height)/'$styleAttr[1])) {
  105.                             $config = []; // reset the config if it was set already before (attributes)
  106.                             $cleanedStyle preg_replace('#[ ]+#'''$styleAttr[1]);
  107.                             $styles explode(';'$cleanedStyle);
  108.                             foreach ($styles as $style) {
  109.                                 if (strpos(trim($style), 'width') === 0) {
  110.                                     if (preg_match('/([0-9]+)(px)/i'$style$match)) {
  111.                                         $config['width'] = $match[1];
  112.                                     }
  113.                                 } elseif (strpos(trim($style), 'height') === 0) {
  114.                                     if (preg_match('/([0-9]+)(px)/i'$style$match)) {
  115.                                         $config['height'] = $match[1];
  116.                                     }
  117.                                 }
  118.                             }
  119.                         }
  120.                         // only create a thumbnail if it is not disabled
  121.                         if (!preg_match('/pimcore_disable_thumbnail="([^"]+)*"/'$oldTag)) {
  122.                             if (!empty($config)) {
  123.                                 $path $element->getThumbnail($config);
  124.                                 $pathHdpi $element->getThumbnail(array_merge($config, ['highResolution' => 2]));
  125.                                 $additionalAttributes = [
  126.                                     'srcset' => $path ' 1x, ' $pathHdpi ' 2x',
  127.                                 ];
  128.                             } elseif ($element->getWidth() > 2000 || $element->getHeight() > 2000) {
  129.                                 // if the image is too large, size it down to 2000px this is the max. for wysiwyg
  130.                                 // for those big images we don't generate a hdpi version
  131.                                 $path $element->getThumbnail([
  132.                                     'width' => 2000,
  133.                                 ]);
  134.                             } else {
  135.                                 // return the original
  136.                                 $path $element->getFullPath();
  137.                             }
  138.                         }
  139.                     }
  140.                     if ($path) {
  141.                         $pattern '/' $linkAttr '="[^"]*"/';
  142.                         $replacement $linkAttr '="' $path '"';
  143.                         if (!empty($additionalAttributes)) {
  144.                             $replacement .= ' ' array_to_html_attribute_string($additionalAttributes);
  145.                         }
  146.                         $newTag preg_replace($pattern$replacement$oldTag);
  147.                         $text str_replace($oldTag$newTag$text);
  148.                     }
  149.                 }
  150.                 if (!$path) {
  151.                     // in case there's a broken internal reference/link
  152.                     if ($matches[1][$i] == 'img') {
  153.                         // remove the entire tag for images
  154.                         $text str_replace($oldTag''$text);
  155.                     } elseif ($matches[1][$i] == 'a') {
  156.                         // just display the text for links
  157.                         $text preg_replace('@' preg_quote($oldTag'@') . '([^\<]+)\</a\>@i''$1'$text);
  158.                     }
  159.                 }
  160.             }
  161.         }
  162.         return $text;
  163.     }
  164.     /**
  165.      * @param string $text
  166.      *
  167.      * @return array
  168.      */
  169.     private static function getElementsTagsInWysiwyg($text)
  170.     {
  171.         if (!is_string($text) || strlen($text) < 1) {
  172.             return [];
  173.         }
  174.         $hash 'elements_raw_wysiwyg_text_' md5($text);
  175.         if (RuntimeCache::isRegistered($hash)) {
  176.             return RuntimeCache::get($hash);
  177.         }
  178.         //$text = Pimcore_Tool_Text::removeLineBreaks($text);
  179.         preg_match_all("@\<(a|img)[^>]*(pimcore_id=\"[0-9]+\")[^>]*(pimcore_type=\"[asset|document|object]+\")[^>]*\>@msUi"$text$matches);
  180.         RuntimeCache::set($hash$matches);
  181.         return $matches;
  182.     }
  183.     /**
  184.      * @param string $text
  185.      *
  186.      * @return array
  187.      */
  188.     private static function getElementsInWysiwyg($text)
  189.     {
  190.         $hash 'elements_wysiwyg_text_' md5($text);
  191.         if (RuntimeCache::isRegistered($hash)) {
  192.             return RuntimeCache::get($hash);
  193.         }
  194.         $elements = [];
  195.         $matches self::getElementsTagsInWysiwyg($text);
  196.         if (count($matches[2]) > 0) {
  197.             for ($i 0$i count($matches[2]); $i++) {
  198.                 preg_match('/[0-9]+/'$matches[2][$i], $idMatches);
  199.                 preg_match('/asset|object|document/'$matches[3][$i], $typeMatches);
  200.                 $id $idMatches[0];
  201.                 $type $typeMatches[0];
  202.                 if ($id && $type) {
  203.                     $elements[] = [
  204.                         'id' => $id,
  205.                         'type' => $type,
  206.                     ];
  207.                 }
  208.             }
  209.         }
  210.         RuntimeCache::set($hash$elements);
  211.         return $elements;
  212.     }
  213.     /**
  214.      * extracts all dependencies to other elements from wysiwyg text
  215.      *
  216.      * @param  string $text
  217.      *
  218.      * @return array
  219.      */
  220.     public static function getDependenciesOfWysiwygText($text)
  221.     {
  222.         $dependencies = [];
  223.         if (!empty($text)) {
  224.             $elements self::getElementsInWysiwyg($text);
  225.             foreach ($elements as $element) {
  226.                 $key $element['type'] . '_' $element['id'];
  227.                 $dependencies[$key] = [
  228.                     'id' => $element['id'],
  229.                     'type' => $element['type'],
  230.                 ];
  231.             }
  232.         }
  233.         return $dependencies;
  234.     }
  235.     /**
  236.      * @param string $text
  237.      * @param array $tags
  238.      *
  239.      * @return array
  240.      */
  241.     public static function getCacheTagsOfWysiwygText($text, array $tags = []): array
  242.     {
  243.         if (!empty($text)) {
  244.             $elements self::getElementsInWysiwyg($text);
  245.             foreach ($elements as $element) {
  246.                 $tag Element\Service::getElementCacheTag($element['type'], $element['id']);
  247.                 $tags[$tag] = $tag;
  248.             }
  249.         }
  250.         return $tags;
  251.     }
  252.     /**
  253.      * @param string $text
  254.      *
  255.      * @return string
  256.      */
  257.     public static function convertToUTF8($text)
  258.     {
  259.         $encoding self::detectEncoding($text);
  260.         if ($encoding) {
  261.             $text iconv($encoding'UTF-8'$text);
  262.         }
  263.         return $text;
  264.     }
  265.     /**
  266.      * @param string $text
  267.      *
  268.      * @return string
  269.      */
  270.     public static function detectEncoding($text)
  271.     {
  272.         // Detect UTF-8, UTF-16 and UTF-32 by BOM
  273.         $utf32_big_endian_bom chr(0x00) . chr(0x00) . chr(0xFE) . chr(0xFF);
  274.         $utf32_little_endian_bom chr(0xFF) . chr(0xFE) . chr(0x00) . chr(0x00);
  275.         $utf16_big_endian_bom chr(0xFE) . chr(0xFF);
  276.         $utf16_little_endian_bom chr(0xFF) . chr(0xFE);
  277.         $utf8_bom chr(0xEF) . chr(0xBB) . chr(0xBF);
  278.         $first2bytes substr($text02);
  279.         $first3bytes substr($text03);
  280.         $first4bytes substr($text03);
  281.         if ($first3bytes === $utf8_bom) {
  282.             return 'UTF-8';
  283.         } elseif ($first4bytes === $utf32_big_endian_bom) {
  284.             return 'UTF-32BE';
  285.         } elseif ($first4bytes === $utf32_little_endian_bom) {
  286.             return 'UTF-32LE';
  287.         } elseif ($first2bytes === $utf16_big_endian_bom) {
  288.             return 'UTF-16BE';
  289.         } elseif ($first2bytes === $utf16_little_endian_bom) {
  290.             return 'UTF-16LE';
  291.         }
  292.         $detector = new EncodingDetector();
  293.         $encoding $detector->getEncoding($text);
  294.         if (empty($encoding)) {
  295.             $encoding 'UTF-8';
  296.         }
  297.         return $encoding;
  298.     }
  299.     /**
  300.      * @param string $string
  301.      *
  302.      * @return string
  303.      */
  304.     public static function getStringAsOneLine($string)
  305.     {
  306.         $string str_replace("\r\n"' '$string);
  307.         $string str_replace("\n"' '$string);
  308.         $string str_replace("\r"' '$string);
  309.         $string str_replace("\t"''$string);
  310.         $string preg_replace('#[ ]+#'' '$string);
  311.         return $string;
  312.     }
  313.     /**
  314.      * @param string $string
  315.      * @param int $length
  316.      *
  317.      * @return string
  318.      */
  319.     public static function cutStringRespectingWhitespace($string$length)
  320.     {
  321.         if ($length strlen($string)) {
  322.             $text substr($string0$length);
  323.             if (false !== ($length strrpos($text' '))) {
  324.                 $text substr($text0$length);
  325.             }
  326.             $string $text '…';
  327.         }
  328.         return $string;
  329.     }
  330. }