Changeset View
Changeset View
Standalone View
Standalone View
src/applications/files/markup/PhabricatorImageRemarkupRule.php
| <?php | <?php | ||||
| final class PhabricatorImageRemarkupRule extends PhutilRemarkupRule { | final class PhabricatorImageRemarkupRule extends PhutilRemarkupRule { | ||||
| const KEY_RULE_EXTERNAL_IMAGE = 'rule.external-image'; | |||||
| public function getPriority() { | public function getPriority() { | ||||
| return 200.0; | return 200.0; | ||||
| } | } | ||||
| public function apply($text) { | public function apply($text) { | ||||
| return preg_replace_callback( | return preg_replace_callback( | ||||
| '@{(image|img) ((?:[^}\\\\]+|\\\\.)*)}@m', | '@{(image|img) ((?:[^}\\\\]+|\\\\.)*)}@m', | ||||
| array($this, 'markupImage'), | array($this, 'markupImage'), | ||||
| $text); | $text); | ||||
| } | } | ||||
| public function markupImage(array $matches) { | public function markupImage(array $matches) { | ||||
| if (!$this->isFlatText($matches[0])) { | if (!$this->isFlatText($matches[0])) { | ||||
| return $matches[0]; | return $matches[0]; | ||||
| } | } | ||||
| $args = array(); | $args = array(); | ||||
| $defaults = array( | $defaults = array( | ||||
| 'uri' => null, | 'uri' => null, | ||||
| 'alt' => null, | 'alt' => null, | ||||
| 'width' => null, | 'width' => null, | ||||
| 'height' => null, | 'height' => null, | ||||
| ); | ); | ||||
| $trimmed_match = trim($matches[2]); | $trimmed_match = trim($matches[2]); | ||||
| if ($this->isURI($trimmed_match)) { | if ($this->isURI($trimmed_match)) { | ||||
| $args['uri'] = new PhutilURI($trimmed_match); | $args['uri'] = $trimmed_match; | ||||
| } else { | } else { | ||||
| $parser = new PhutilSimpleOptions(); | $parser = new PhutilSimpleOptions(); | ||||
| $keys = $parser->parse($trimmed_match); | $keys = $parser->parse($trimmed_match); | ||||
| $uri_key = ''; | $uri_key = ''; | ||||
| foreach (array('src', 'uri', 'url') as $key) { | foreach (array('src', 'uri', 'url') as $key) { | ||||
| if (array_key_exists($key, $keys)) { | if (array_key_exists($key, $keys)) { | ||||
| $uri_key = $key; | $uri_key = $key; | ||||
| } | } | ||||
| } | } | ||||
| if ($uri_key) { | if ($uri_key) { | ||||
| $args['uri'] = new PhutilURI($keys[$uri_key]); | $args['uri'] = $keys[$uri_key]; | ||||
| } | } | ||||
| $args += $keys; | $args += $keys; | ||||
| } | } | ||||
| $args += $defaults; | $args += $defaults; | ||||
| if ($args['uri']) { | if (!strlen($args['uri'])) { | ||||
| return $matches[0]; | |||||
| } | |||||
| // Make sure this is something that looks roughly like a real URI. We'll | |||||
| // validate it more carefully before proxying it, but if whatever the user | |||||
| // has typed isn't even close, just decline to activate the rule behavior. | |||||
| try { | |||||
| $uri = new PhutilURI($args['uri']); | |||||
| if (!strlen($uri->getProtocol())) { | |||||
| return $matches[0]; | |||||
| } | |||||
| $args['uri'] = (string)$uri; | |||||
| } catch (Exception $ex) { | |||||
| return $matches[0]; | |||||
| } | |||||
| $engine = $this->getEngine(); | |||||
| $metadata_key = self::KEY_RULE_EXTERNAL_IMAGE; | |||||
| $metadata = $engine->getTextMetadata($metadata_key, array()); | |||||
| $token = $engine->storeText('<img>'); | |||||
| $metadata[] = array( | |||||
| 'token' => $token, | |||||
| 'args' => $args, | |||||
| ); | |||||
| $engine->setTextMetadata($metadata_key, $metadata); | |||||
| return $token; | |||||
| } | |||||
| public function didMarkupText() { | |||||
| $engine = $this->getEngine(); | |||||
| $metadata_key = self::KEY_RULE_EXTERNAL_IMAGE; | |||||
| $images = $engine->getTextMetadata($metadata_key, array()); | |||||
| $engine->setTextMetadata($metadata_key, array()); | |||||
| if (!$images) { | |||||
| return; | |||||
| } | |||||
| foreach ($images as $image) { | |||||
| $args = $image['args']; | |||||
| $src_uri = id(new PhutilURI('/file/imageproxy/')) | $src_uri = id(new PhutilURI('/file/imageproxy/')) | ||||
| ->setQueryParam('uri', (string)$args['uri']); | ->setQueryParam('uri', $args['uri']); | ||||
| $img = $this->newTag( | $img = $this->newTag( | ||||
| 'img', | 'img', | ||||
| array( | array( | ||||
| 'src' => $src_uri, | 'src' => $src_uri, | ||||
| 'alt' => $args['alt'], | 'alt' => $args['alt'], | ||||
| 'width' => $args['width'], | 'width' => $args['width'], | ||||
| 'height' => $args['height'], | 'height' => $args['height'], | ||||
| )); | )); | ||||
| return $this->getEngine()->storeText($img); | |||||
| } else { | $engine->overwriteStoredText($image['token'], $img); | ||||
| return $matches[0]; | |||||
| } | } | ||||
| } | } | ||||
| private function isURI($uri_string) { | private function isURI($uri_string) { | ||||
| // Very simple check to make sure it starts with either http or https. | // Very simple check to make sure it starts with either http or https. | ||||
| // If it does, we'll try to treat it like a valid URI | // If it does, we'll try to treat it like a valid URI | ||||
| return preg_match('~^https?\:\/\/.*\z~i', $uri_string); | return preg_match('~^https?\:\/\/.*\z~i', $uri_string); | ||||
| } | } | ||||
| } | } | ||||