Allow hotlinking images
This commit is contained in:
25
README.md
25
README.md
@@ -220,20 +220,29 @@ Clicking a thumbnail opens a lightbox viewer. Thumbnails are generated and cache
|
|||||||
|
|
||||||
```
|
```
|
||||||
{{image>/Scape/photos/picture.jpg|This is the caption}}
|
{{image>/Scape/photos/picture.jpg|This is the caption}}
|
||||||
{{image>/Scape/photos/picture.jpg?400|Resized to 400px width}}
|
{{image>/Scape/photos/picture.jpg|Caption|400}}
|
||||||
{{image>/Scape/photos/picture.jpg?400x300|Fixed dimensions}}
|
{{image>/Scape/photos/picture.jpg|Caption|400x300}}
|
||||||
{{image>/Scape/photos/picture.jpg?left|Float left}}
|
{{image>/Scape/photos/picture.jpg|Caption|left}}
|
||||||
{{image>/Scape/photos/picture.jpg?400¢er|Resized and centered}}
|
{{image>/Scape/photos/picture.jpg|Caption|400¢er}}
|
||||||
|
{{image>https://example.com/images/picture.jpg|Remote image caption}}
|
||||||
|
{{image>https://example.com/images/picture.jpg|Remote caption|400x300&left}}
|
||||||
```
|
```
|
||||||
|
|
||||||
Renders a Wikipedia-style image box with optional caption. Parameters after `?` are separated by `&`:
|
Renders a Wikipedia-style image box with optional caption. The syntax uses pipe-separated parts:
|
||||||
|
|
||||||
- Size: `?200` (width) or `?200x150` (width × height)
|
- `{{image>path|caption}}` – Image with caption (uses defaults)
|
||||||
- Alignment: `?left`, `?right` (default), or `?center`
|
- `{{image>path|caption|options}}` – Image with caption and options
|
||||||
- Combined: `?400&left` or `?400x300¢er`
|
|
||||||
|
Options (in the third part, separated by `&`):
|
||||||
|
|
||||||
|
- Size: `200` (width) or `200x150` (width × height)
|
||||||
|
- Alignment: `left`, `right` (default), or `center`
|
||||||
|
- Combined: `400&left` or `400x300¢er`
|
||||||
|
|
||||||
The image links to the full-size version when clicked.
|
The image links to the full-size version when clicked.
|
||||||
|
|
||||||
|
Remote images (HTTP/HTTPS URLs) are linked directly without proxying or thumbnailing.
|
||||||
|
|
||||||
### 5) Open a local path/folder (best-effort)
|
### 5) Open a local path/folder (best-effort)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
2
file.php
2
file.php
@@ -224,7 +224,7 @@ try {
|
|||||||
echo 'Path not readable: ' . $pathInfo['path'];
|
echo 'Path not readable: ' . $pathInfo['path'];
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
[$ext, $mime, $download] = mimetype($pathInfo['path'], false);
|
[, $mime, $download] = mimetype($pathInfo['path'], false);
|
||||||
|
|
||||||
// Optional thumbnail mode: ?thumb=1&w=150&h=150
|
// Optional thumbnail mode: ?thumb=1&w=150&h=150
|
||||||
$thumb = (int)$INPUT->int('thumb');
|
$thumb = (int)$INPUT->int('thumb');
|
||||||
|
|||||||
@@ -9,6 +9,22 @@ namespace dokuwiki\plugin\luxtools;
|
|||||||
*/
|
*/
|
||||||
class ThumbnailHelper
|
class ThumbnailHelper
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Check if a string is a HTTP/HTTPS URL.
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isRemoteUrl(string $url): bool
|
||||||
|
{
|
||||||
|
if ($url === '') return false;
|
||||||
|
$parts = @parse_url($url);
|
||||||
|
if (!is_array($parts)) return false;
|
||||||
|
if (empty($parts['scheme']) || empty($parts['host'])) return false;
|
||||||
|
$scheme = strtolower((string)$parts['scheme']);
|
||||||
|
return in_array($scheme, ['http', 'https'], true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get thumbnail URL and metadata for rendering.
|
* Get thumbnail URL and metadata for rendering.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -45,34 +45,26 @@ class syntax_plugin_luxtools_image extends SyntaxPlugin
|
|||||||
// Remove the leading {{image> and trailing }}
|
// Remove the leading {{image> and trailing }}
|
||||||
$match = substr($match, strlen('{{image>'), -2);
|
$match = substr($match, strlen('{{image>'), -2);
|
||||||
|
|
||||||
// Split path and caption by |
|
// Split by | into: path, caption, options
|
||||||
$parts = explode('|', $match, 2);
|
// Format: {{image>path|caption|options}}
|
||||||
|
$parts = explode('|', $match, 3);
|
||||||
$pathPart = trim($parts[0]);
|
$pathPart = trim($parts[0]);
|
||||||
$caption = isset($parts[1]) ? trim($parts[1]) : '';
|
$caption = isset($parts[1]) ? trim($parts[1]) : '';
|
||||||
|
$optionStr = isset($parts[2]) ? trim($parts[2]) : '';
|
||||||
|
|
||||||
// Parse optional parameters from path (e.g., /path/image.jpg?200x150&right)
|
// Parse options from third part (e.g., "200x150&right")
|
||||||
// Supported formats:
|
|
||||||
// ?200 - width only
|
|
||||||
// ?200x150 - width and height
|
|
||||||
// ?left - alignment only (left, right, center)
|
|
||||||
// ?200&right - width and alignment
|
|
||||||
// ?200x150¢er - full options
|
|
||||||
$width = null;
|
$width = null;
|
||||||
$height = null;
|
$height = null;
|
||||||
$align = null; // Will use default if not specified
|
$align = null;
|
||||||
|
|
||||||
if (strpos($pathPart, '?') !== false) {
|
if ($optionStr !== '') {
|
||||||
[$pathPart, $paramStr] = explode('?', $pathPart, 2);
|
$optionParts = explode('&', $optionStr);
|
||||||
$paramParts = explode('&', $paramStr);
|
foreach ($optionParts as $param) {
|
||||||
|
|
||||||
foreach ($paramParts as $param) {
|
|
||||||
$param = trim($param);
|
$param = trim($param);
|
||||||
if ($param === '') continue;
|
if ($param === '') continue;
|
||||||
|
|
||||||
// Check if it's an alignment keyword
|
|
||||||
if (in_array($param, ['left', 'right', 'center'], true)) {
|
if (in_array($param, ['left', 'right', 'center'], true)) {
|
||||||
$align = $param;
|
$align = $param;
|
||||||
// Check if it's a size specification (digits, optionally with 'x' and more digits)
|
|
||||||
} elseif (preg_match('/^(\d+)(?:x(\d+))?$/', $param, $m)) {
|
} elseif (preg_match('/^(\d+)(?:x(\d+))?$/', $param, $m)) {
|
||||||
$width = (int)$m[1];
|
$width = (int)$m[1];
|
||||||
if (isset($m[2]) && $m[2] !== '') {
|
if (isset($m[2]) && $m[2] !== '') {
|
||||||
@@ -82,10 +74,12 @@ class syntax_plugin_luxtools_image extends SyntaxPlugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$path = Path::cleanPath($pathPart, false);
|
$isRemote = ThumbnailHelper::isRemoteUrl($pathPart);
|
||||||
|
$path = $isRemote ? $pathPart : Path::cleanPath($pathPart, false);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'path' => $path,
|
'path' => $path,
|
||||||
|
'is_remote' => $isRemote,
|
||||||
'caption' => $caption,
|
'caption' => $caption,
|
||||||
'align' => $align,
|
'align' => $align,
|
||||||
'width' => $width,
|
'width' => $width,
|
||||||
@@ -120,6 +114,23 @@ class syntax_plugin_luxtools_image extends SyntaxPlugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($data['is_remote'])) {
|
||||||
|
if (empty($data['path']) || !ThumbnailHelper::isRemoteUrl($data['path'])) {
|
||||||
|
$renderer->cdata('[n/a: Invalid URL]');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remote images: link directly, no proxying or thumbnailing
|
||||||
|
$thumb = [
|
||||||
|
'url' => $data['path'],
|
||||||
|
'isFinal' => true,
|
||||||
|
'thumbUrl' => $data['path'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->renderImageBox($renderer, $thumb, $data['path'], $data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$pathHelper = new Path($this->getConf('paths'));
|
$pathHelper = new Path($this->getConf('paths'));
|
||||||
// Use addTrailingSlash=false since this is a file path, not a directory
|
// Use addTrailingSlash=false since this is a file path, not a directory
|
||||||
@@ -162,7 +173,7 @@ class syntax_plugin_luxtools_image extends SyntaxPlugin
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Build full-size URL for linking
|
// Build full-size URL for linking
|
||||||
$fullUrl = $this->buildFileUrl($pathInfo, null, null, false);
|
$fullUrl = $this->buildImageUrl($pathInfo, null, null, false);
|
||||||
|
|
||||||
$this->renderImageBox($renderer, $thumb, $fullUrl, $data);
|
$this->renderImageBox($renderer, $thumb, $fullUrl, $data);
|
||||||
|
|
||||||
@@ -170,15 +181,15 @@ class syntax_plugin_luxtools_image extends SyntaxPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the file.php URL for the image.
|
* Build the file.php URL for a local image.
|
||||||
*
|
*
|
||||||
* @param array $pathInfo Path info from Path helper
|
* @param array $pathInfo Path info array from Path helper
|
||||||
* @param int|null $width Optional width
|
* @param int|null $width Optional width
|
||||||
* @param int|null $height Optional height
|
* @param int|null $height Optional height
|
||||||
* @param bool $thumbnail Whether to generate a thumbnail
|
* @param bool $thumbnail Whether to generate a thumbnail
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildFileUrl(array $pathInfo, ?int $width, ?int $height, bool $thumbnail = false): string
|
protected function buildImageUrl(array $pathInfo, ?int $width, ?int $height, bool $thumbnail): string
|
||||||
{
|
{
|
||||||
global $ID;
|
global $ID;
|
||||||
|
|
||||||
@@ -189,9 +200,8 @@ class syntax_plugin_luxtools_image extends SyntaxPlugin
|
|||||||
];
|
];
|
||||||
|
|
||||||
if ($thumbnail && ($width !== null || $height !== null)) {
|
if ($thumbnail && ($width !== null || $height !== null)) {
|
||||||
// Enable thumbnail mode (same as gallery logic)
|
|
||||||
$params['thumb'] = 1;
|
$params['thumb'] = 1;
|
||||||
$params['q'] = 80; // JPEG quality
|
$params['q'] = 80;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($width !== null) {
|
if ($width !== null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user