Page MenuHomePhorge

No OneTemporary

diff --git a/resources/builtin/image-100x100.png b/resources/builtin/image-100x100.png
new file mode 100644
index 0000000000..c56a9aa083
Binary files /dev/null and b/resources/builtin/image-100x100.png differ
diff --git a/resources/builtin/image-220x220.png b/resources/builtin/image-220x220.png
new file mode 100644
index 0000000000..928b5b05eb
Binary files /dev/null and b/resources/builtin/image-220x220.png differ
diff --git a/resources/builtin/image-280x210.png b/resources/builtin/image-280x210.png
new file mode 100644
index 0000000000..48237b045e
Binary files /dev/null and b/resources/builtin/image-280x210.png differ
diff --git a/src/applications/files/controller/PhabricatorFileTransformController.php b/src/applications/files/controller/PhabricatorFileTransformController.php
index 9b893b9528..a7fcbc3c0a 100644
--- a/src/applications/files/controller/PhabricatorFileTransformController.php
+++ b/src/applications/files/controller/PhabricatorFileTransformController.php
@@ -1,157 +1,168 @@
<?php
final class PhabricatorFileTransformController
extends PhabricatorFileController {
public function shouldRequireLogin() {
return false;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
// NOTE: This is a public/CDN endpoint, and permission to see files is
// controlled by knowing the secret key, not by authentication.
$source_phid = $request->getURIData('phid');
$file = id(new PhabricatorFileQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs(array($source_phid))
->executeOne();
if (!$file) {
return new Aphront404Response();
}
$secret_key = $request->getURIData('key');
if (!$file->validateSecretKey($secret_key)) {
return new Aphront403Response();
}
$transform = $request->getURIData('transform');
$xform = id(new PhabricatorTransformedFile())
->loadOneWhere(
'originalPHID = %s AND transform = %s',
$source_phid,
$transform);
if ($xform) {
return $this->buildTransformedFileResponse($xform);
}
$type = $file->getMimeType();
if (!$file->isViewableInBrowser() || !$file->isTransformableImage()) {
return $this->buildDefaultTransformation($file, $transform);
}
// We're essentially just building a cache here and don't need CSRF
// protection.
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$xformed_file = null;
$xforms = PhabricatorFileTransform::getAllTransforms();
if (isset($xforms[$transform])) {
$xform = $xforms[$transform];
if ($xform->canApplyTransform($file)) {
- $xformed_file = $xforms[$transform]->applyTransform($file);
+ try {
+ $xformed_file = $xforms[$transform]->applyTransform($file);
+ } catch (Exception $ex) {
+ // TODO: Provide a diagnostic mode to surface these to the viewer.
+
+ // In normal transform mode, we ignore failures and generate a
+ // default transform instead.
+ }
+ }
+
+ if (!$xformed_file) {
+ $xformed_file = $xform->getDefaultTransform($file);
}
}
if (!$xformed_file) {
switch ($transform) {
case 'thumb-profile':
$xformed_file = $this->executeThumbTransform($file, 50, 50);
break;
case 'thumb-280x210':
$xformed_file = $this->executeThumbTransform($file, 280, 210);
break;
case 'preview-100':
$xformed_file = $this->executePreviewTransform($file, 100);
break;
case 'preview-220':
$xformed_file = $this->executePreviewTransform($file, 220);
break;
default:
return new Aphront400Response();
}
}
if (!$xformed_file) {
return new Aphront400Response();
}
$xform = id(new PhabricatorTransformedFile())
->setOriginalPHID($source_phid)
->setTransform($transform)
->setTransformedPHID($xformed_file->getPHID())
->save();
return $this->buildTransformedFileResponse($xform);
}
private function buildDefaultTransformation(
PhabricatorFile $file,
$transform) {
static $regexps = array(
'@application/zip@' => 'zip',
'@image/@' => 'image',
'@application/pdf@' => 'pdf',
'@.*@' => 'default',
);
$type = $file->getMimeType();
$prefix = 'default';
foreach ($regexps as $regexp => $implied_prefix) {
if (preg_match($regexp, $type)) {
$prefix = $implied_prefix;
break;
}
}
switch ($transform) {
case 'thumb-280x210':
$suffix = '280x210';
break;
case 'preview-100':
$suffix = '.p100';
break;
default:
throw new Exception('Unsupported transformation type!');
}
$path = celerity_get_resource_uri(
"rsrc/image/icon/fatcow/thumbnails/{$prefix}{$suffix}.png");
return id(new AphrontRedirectResponse())
->setURI($path);
}
private function buildTransformedFileResponse(
PhabricatorTransformedFile $xform) {
$file = id(new PhabricatorFileQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs(array($xform->getTransformedPHID()))
->executeOne();
if (!$file) {
return new Aphront404Response();
}
// TODO: We could just delegate to the file view controller instead,
// which would save the client a roundtrip, but is slightly more complex.
return $file->getRedirectResponse();
}
private function executePreviewTransform(PhabricatorFile $file, $size) {
$xformer = new PhabricatorImageTransformer();
return $xformer->executePreviewTransform($file, $size);
}
private function executeThumbTransform(PhabricatorFile $file, $x, $y) {
$xformer = new PhabricatorImageTransformer();
return $xformer->executeThumbTransform($file, $x, $y);
}
}
diff --git a/src/applications/files/transform/PhabricatorFileThumbnailTransform.php b/src/applications/files/transform/PhabricatorFileThumbnailTransform.php
index d88451a0de..75c16e2ddf 100644
--- a/src/applications/files/transform/PhabricatorFileThumbnailTransform.php
+++ b/src/applications/files/transform/PhabricatorFileThumbnailTransform.php
@@ -1,74 +1,90 @@
<?php
final class PhabricatorFileThumbnailTransform
extends PhabricatorFileImageTransform {
const TRANSFORM_PROFILE = 'profile';
const TRANSFORM_PINBOARD = 'pinboard';
const TRANSFORM_THUMBGRID = 'thumbgrid';
const TRANSFORM_PREVIEW = 'preview';
private $name;
private $key;
private $dstX;
private $dstY;
public function setName($name) {
$this->name = $name;
return $this;
}
public function setKey($key) {
$this->key = $key;
return $this;
}
public function setDimensions($x, $y) {
$this->dstX = $x;
$this->dstY = $y;
return $this;
}
public function getTransformName() {
return $this->name;
}
public function getTransformKey() {
return $this->key;
}
public function generateTransforms() {
return array(
id(new PhabricatorFileThumbnailTransform())
->setName(pht("Profile (100px \xC3\x97 100px)"))
->setKey(self::TRANSFORM_PROFILE)
->setDimensions(100, 100),
id(new PhabricatorFileThumbnailTransform())
->setName(pht("Pinboard (280px \xC3\x97 210px)"))
->setKey(self::TRANSFORM_PINBOARD)
->setDimensions(280, 210),
id(new PhabricatorFileThumbnailTransform())
->setName(pht('Thumbgrid (100px)'))
->setKey(self::TRANSFORM_THUMBGRID)
->setDimensions(100, null),
id(new PhabricatorFileThumbnailTransform())
->setName(pht('Preview (220px)'))
->setKey(self::TRANSFORM_PREVIEW)
->setDimensions(220, null),
);
}
public function applyTransform(PhabricatorFile $file) {
$x = $this->dstX;
$y = $this->dstY;
$xformer = new PhabricatorImageTransformer();
if ($y === null) {
return $xformer->executePreviewTransform($file, $x);
} else {
return $xformer->executeThumbTransform($file, $x, $y);
}
}
+ public function getDefaultTransform(PhabricatorFile $file) {
+ $x = (int)$this->dstX;
+ $y = (int)$this->dstY;
+ $name = 'image-'.$x.'x'.nonempty($y, $x).'.png';
+
+ $params = array(
+ 'name' => $name,
+ 'canCDN' => true,
+ );
+
+ $root = dirname(phutil_get_library_root('phabricator'));
+ $data = Filesystem::readFile($root.'/resources/builtin/'.$name);
+
+ return PhabricatorFile::newFromFileData($data, $params);
+ }
+
}
diff --git a/src/applications/files/transform/PhabricatorFileTransform.php b/src/applications/files/transform/PhabricatorFileTransform.php
index 7a36641140..f12aefd3ed 100644
--- a/src/applications/files/transform/PhabricatorFileTransform.php
+++ b/src/applications/files/transform/PhabricatorFileTransform.php
@@ -1,44 +1,48 @@
<?php
abstract class PhabricatorFileTransform extends Phobject {
abstract public function getTransformName();
abstract public function getTransformKey();
abstract public function canApplyTransform(PhabricatorFile $file);
abstract public function applyTransform(PhabricatorFile $file);
+ public function getDefaultTransform(PhabricatorFile $file) {
+ return null;
+ }
+
public function generateTransforms() {
return array($this);
}
public static function getAllTransforms() {
static $map;
if ($map === null) {
$xforms = id(new PhutilSymbolLoader())
->setAncestorClass(__CLASS__)
->loadObjects();
$result = array();
foreach ($xforms as $xform_template) {
foreach ($xform_template->generateTransforms() as $xform) {
$key = $xform->getTransformKey();
if (isset($result[$key])) {
throw new Exception(
pht(
'Two %s objects define the same transform key ("%s"), but '.
'each transform must have a unique key.',
__CLASS__,
$key));
}
$result[$key] = $xform;
}
}
$map = $result;
}
return $map;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 19, 13:04 (3 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1124873
Default Alt Text
(10 KB)

Event Timeline