mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-01-04 01:01:41 +09:00
Add manual image conversion for admin
This commit is contained in:
parent
818fd54b00
commit
84acc21817
12 changed files with 312 additions and 23 deletions
|
|
@ -14,11 +14,14 @@
|
|||
<action name="procFileGetList" type="controller" permission="root" />
|
||||
|
||||
<action name="dispFileAdminList" type="view" admin_index="true" menu_name="file" menu_index="true" />
|
||||
<action name="dispFileAdminEdit" type="view" menu_name="file" />
|
||||
<action name="dispFileAdminUploadConfig" type="view" menu_name="file" />
|
||||
<action name="dispFileAdminDownloadConfig" type="view" menu_name="file" />
|
||||
<action name="dispFileAdminOtherConfig" type="view" menu_name="file" />
|
||||
|
||||
<action name="procFileAdminAddCart" type="controller" />
|
||||
<action name="procFileAdminEditFileName" type="controller" />
|
||||
<action name="procFileAdminEditImage" type="controller" />
|
||||
<action name="procFileAdminDeleteChecked" type="controller" ruleset="deleteChecked" />
|
||||
<action name="procFileAdminInsertUploadConfig" type="controller" ruleset="insertConfig" />
|
||||
<action name="procFileAdminInsertDownloadConfig" type="controller" />
|
||||
|
|
|
|||
|
|
@ -296,6 +296,142 @@ class FileAdminController extends File
|
|||
else $_SESSION['file_management'][$output->file_srl] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit filename
|
||||
*/
|
||||
public function procFileAdminEditFileName()
|
||||
{
|
||||
$file_srl = Context::get('file_srl');
|
||||
if (!$file_srl)
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\InvalidRequest;
|
||||
}
|
||||
$file = FileModel::getFile($file_srl);
|
||||
if (!$file)
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\TargetNotFound;
|
||||
}
|
||||
$file_name = trim(utf8_normalize_spaces(utf8_clean(Context::get('file_name'))));
|
||||
$file_name = Rhymix\Framework\Filters\FilenameFilter::clean($file_name);
|
||||
if ($file_name === '')
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\InvalidRequest;
|
||||
}
|
||||
|
||||
$output = executeQuery('file.updateFileName', [
|
||||
'file_srl' => $file_srl,
|
||||
'source_filename' => $file_name,
|
||||
]);
|
||||
if (!$output->toBool())
|
||||
{
|
||||
return $output;
|
||||
}
|
||||
|
||||
$this->setMessage('success_updated');
|
||||
$this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl(['module' => 'admin', 'act' => 'dispFileAdminEdit', 'file_srl' => $file_srl]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit image
|
||||
*/
|
||||
public function procFileAdminEditImage()
|
||||
{
|
||||
$file_srl = Context::get('file_srl');
|
||||
if (!$file_srl)
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\InvalidRequest;
|
||||
}
|
||||
$file = FileModel::getFile($file_srl);
|
||||
if (!$file)
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\TargetNotFound;
|
||||
}
|
||||
|
||||
// Validate user input.
|
||||
$width = intval(Context::get('new_width'));
|
||||
$height = intval(Context::get('new_height'));
|
||||
$format = Context::get('format');
|
||||
$quality = intval(Context::get('quality'));
|
||||
if ($width <= 0 || $height <= 0 || !in_array($format, ['jpg', 'png', 'webp']) || $quality <= 0 || $quality > 100)
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\InvalidRequest;
|
||||
}
|
||||
|
||||
// Generate filenames.
|
||||
$uploaded_filename = FileHandler::getRealPath($file->uploaded_filename);
|
||||
$temp_filename = \RX_BASEDIR . 'files/cache/temp/' . Rhymix\Framework\Security::getRandom(32, 'hex') . '.' . $format;
|
||||
$new_filename = preg_replace('/\.[a-z]+$/', '.' . $format, $file->source_filename);
|
||||
$del_filename = null;
|
||||
|
||||
// Should this file be moved from binaries to images?
|
||||
if (str_starts_with($uploaded_filename, \RX_BASEDIR . 'files/attach/binaries/'))
|
||||
{
|
||||
$del_filename = $uploaded_filename;
|
||||
$uploaded_filename = preg_replace('!/files/attach/binaries/!', '/files/attach/images/', $uploaded_filename, 1) . '.' . $format;
|
||||
}
|
||||
|
||||
// Resize the image using GD or ImageMagick.
|
||||
$config = FileModel::getFileConfig();
|
||||
$result = FileHandler::createImageFile(FileHandler::getRealPath($file->uploaded_filename), $temp_filename, $width, $height, $format, 'fill', $quality);
|
||||
if (!$result && !empty($config->magick_command))
|
||||
{
|
||||
$command = vsprintf('%s %s -resize %dx%d -quality %d %s %s %s', [
|
||||
\RX_WINDOWS ? escapeshellarg($config->magick_command) : $config->magick_command,
|
||||
escapeshellarg(FileHandler::getRealPath($file->uploaded_filename)),
|
||||
$width, $height, $quality,
|
||||
'-auto-orient -strip',
|
||||
'-limit memory 64MB -limit map 128MB -limit disk 1GB',
|
||||
escapeshellarg($temp_filename),
|
||||
]);
|
||||
@exec($command, $output, $return_var);
|
||||
$result = $return_var === 0 ? true : false;
|
||||
}
|
||||
|
||||
// If successfully resized, replace original file and update the image size in DB.
|
||||
if ($result && Rhymix\Framework\Storage::exists($temp_filename) && filesize($temp_filename) > 0)
|
||||
{
|
||||
$moved = Rhymix\Framework\Storage::move($temp_filename, $uploaded_filename);
|
||||
if (!$moved)
|
||||
{
|
||||
throw new Rhymix\Framework\Exception;
|
||||
}
|
||||
if ($del_filename)
|
||||
{
|
||||
Rhymix\Framework\Storage::delete($del_filename);
|
||||
}
|
||||
|
||||
clearstatcache(true, $uploaded_filename);
|
||||
$filesize = filesize($uploaded_filename);
|
||||
$relative_path = preg_replace('!^' . preg_quote(\RX_BASEDIR, '!') . '!', './', $uploaded_filename, 1);
|
||||
|
||||
$updated = executeQuery('file.updateFile', [
|
||||
'file_srl' => $file_srl,
|
||||
'module_srl' => $file->module_srl,
|
||||
'upload_target_srl' => $file->upload_target_srl,
|
||||
'source_filename' => $new_filename,
|
||||
'uploaded_filename' => $relative_path,
|
||||
'direct_download' => 'Y',
|
||||
'mime_type' => Rhymix\Framework\MIME::getTypeByFilename($new_filename),
|
||||
'original_type' => $file->original_type ?: $file->mime_type,
|
||||
'is_cover' => $file->cover_image,
|
||||
'file_size' => $filesize,
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
]);
|
||||
if (!$updated->toBool())
|
||||
{
|
||||
return $updated;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Rhymix\Framework\Exception;
|
||||
}
|
||||
|
||||
$this->setMessage('success_updated');
|
||||
$this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl(['module' => 'admin', 'act' => 'dispFileAdminEdit', 'file_srl' => $file_srl]));
|
||||
}
|
||||
}
|
||||
/* End of file file.admin.controller.php */
|
||||
/* Location: ./modules/file/file.admin.controller.php */
|
||||
|
|
|
|||
|
|
@ -6,20 +6,12 @@
|
|||
*/
|
||||
class FileAdminView extends File
|
||||
{
|
||||
/**
|
||||
* Initialization
|
||||
* @return void
|
||||
*/
|
||||
function init()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Display output list (for administrator)
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
function dispFileAdminList()
|
||||
public function dispFileAdminList()
|
||||
{
|
||||
// Options to get a list
|
||||
$args = new stdClass();
|
||||
|
|
@ -213,11 +205,35 @@ class FileAdminView extends File
|
|||
}
|
||||
|
||||
/**
|
||||
* Upload config screen
|
||||
*
|
||||
* @return Object
|
||||
* File edit screen
|
||||
*/
|
||||
function dispFileAdminUploadConfig()
|
||||
public function dispFileAdminEdit()
|
||||
{
|
||||
$file_srl = intval(Context::get('file_srl'));
|
||||
if (!$file_srl)
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\InvalidRequest;
|
||||
}
|
||||
$file = FileModel::getFile($file_srl);
|
||||
if (!$file)
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\TargetNotFound;
|
||||
}
|
||||
|
||||
$config = FileModel::getFileConfig();
|
||||
Context::set('config', $config);
|
||||
Context::set('file', $file);
|
||||
Context::set('is_ffmpeg', function_exists('exec') && !empty($config->ffmpeg_command) && Rhymix\Framework\Storage::isExecutable($config->ffmpeg_command) && !empty($config->ffprobe_command) && Rhymix\Framework\Storage::isExecutable($config->ffprobe_command));
|
||||
Context::set('is_magick', function_exists('exec') && !empty($config->magick_command) && Rhymix\Framework\Storage::isExecutable($config->magick_command));
|
||||
|
||||
$this->setTemplatePath($this->module_path . 'tpl');
|
||||
$this->setTemplateFile('file_edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload config screen
|
||||
*/
|
||||
public function dispFileAdminUploadConfig()
|
||||
{
|
||||
$oFileModel = getModel('file');
|
||||
$config = $oFileModel->getFileConfig();
|
||||
|
|
@ -233,10 +249,8 @@ class FileAdminView extends File
|
|||
|
||||
/**
|
||||
* Download config screen
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
function dispFileAdminDownloadConfig()
|
||||
public function dispFileAdminDownloadConfig()
|
||||
{
|
||||
$oFileModel = getModel('file');
|
||||
$config = $oFileModel->getFileConfig();
|
||||
|
|
@ -249,10 +263,8 @@ class FileAdminView extends File
|
|||
|
||||
/**
|
||||
* Other config screen
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
function dispFileAdminOtherConfig()
|
||||
public function dispFileAdminOtherConfig()
|
||||
{
|
||||
$oFileModel = getModel('file');
|
||||
$config = $oFileModel->getFileConfig();
|
||||
|
|
|
|||
|
|
@ -132,3 +132,6 @@ $lang->msg_cannot_use_exec = 'The exec() function is disabled on this server.';
|
|||
$lang->msg_cannot_use_ffmpeg = 'In order to use this feature, PHP must be able to execute \'ffmpeg\' and \'ffprobe\' commands.';
|
||||
$lang->msg_cannot_use_exif = 'In order to use this feature, PHP must be installed with the \'exif\' extension.';
|
||||
$lang->msg_need_magick = 'In order to handle AVIF and HEIC formats, PHP must be able to execute the \'magick\' command from ImageMagick 7.x or higher.';
|
||||
$lang->image_conversion = 'Image conversion';
|
||||
$lang->image_size = 'Image size';
|
||||
$lang->image_format = 'Image format';
|
||||
|
|
|
|||
|
|
@ -135,3 +135,6 @@ $lang->msg_cannot_use_exec = '이 서버에서 exec() 함수를 사용할 수
|
|||
$lang->msg_cannot_use_ffmpeg = '이 기능을 사용하려면 PHP에서 ffmpeg 및 ffprobe 명령을 실행할 수 있어야 합니다.';
|
||||
$lang->msg_cannot_use_exif = '이 기능을 사용하려면 PHP exif 확장모듈이 필요합니다.';
|
||||
$lang->msg_need_magick = 'AVIF, HEIC 변환을 위해서는 PHP에서 ImageMagick 7.x 이상의 magick 명령을 실행할 수 있어야 합니다.';
|
||||
$lang->image_conversion = '이미지 변환';
|
||||
$lang->image_size = '이미지 크기';
|
||||
$lang->image_format = '이미지 포맷';
|
||||
|
|
|
|||
|
|
@ -3,11 +3,19 @@
|
|||
<table name="files" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="module_srl" var="module_srl" filter="number" notnull="notnull" />
|
||||
<column name="upload_target_srl" var="upload_target_srl" filter="number" notnull="notnull" />
|
||||
<column name="upload_target_type" var="upload_target_type" />
|
||||
<column name="module_srl" var="module_srl" filter="number" notnull="notnull" />
|
||||
<column name="source_filename" var="source_filename" />
|
||||
<column name="uploaded_filename" var="uploaded_filename" notnull="notnull" minlength="1" maxlength="250" />
|
||||
<column name="cover_image" var="is_cover" default="N" />
|
||||
<column name="direct_download" var="direct_download" />
|
||||
<column name="mime_type" var="mime_type" />
|
||||
<column name="original_type" var="original_type" />
|
||||
<column name="file_size" var="file_size" />
|
||||
<column name="width" var="width" />
|
||||
<column name="height" var="height" />
|
||||
<column name="duration" var="duration" />
|
||||
</columns>
|
||||
<conditions>
|
||||
<condition operation="equal" column="file_srl" var="file_srl" filter="number" notnull="notnull" />
|
||||
|
|
|
|||
11
modules/file/queries/updateFileName.xml
Normal file
11
modules/file/queries/updateFileName.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<query id="updateFileName" action="update">
|
||||
<tables>
|
||||
<table name="files" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="source_filename" var="source_filename" notnull="notnull" />
|
||||
</columns>
|
||||
<conditions>
|
||||
<condition operation="equal" column="file_srl" var="file_srl" filter="number" notnull="notnull" />
|
||||
</conditions>
|
||||
</query>
|
||||
|
|
@ -2,4 +2,8 @@
|
|||
margin-top: -10px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
.x_help-block .preset_size {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
|
|
|||
83
modules/file/tpl/file_edit.html
Normal file
83
modules/file/tpl/file_edit.html
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<include target="header.html" />
|
||||
|
||||
<div cond="$XE_VALIDATOR_MESSAGE && $XE_VALIDATOR_ID == 'modules/file/tpl/edit/1'" class="message {$XE_VALIDATOR_MESSAGE_TYPE}">
|
||||
<p>{$XE_VALIDATOR_MESSAGE}</p>
|
||||
</div>
|
||||
|
||||
<div cond="$XE_VALIDATOR_MESSAGE && $XE_VALIDATOR_ID == 'modules/file/tpl/edit/2'" class="message {$XE_VALIDATOR_MESSAGE_TYPE}">
|
||||
<p>{$XE_VALIDATOR_MESSAGE}</p>
|
||||
</div>
|
||||
|
||||
<section class="section">
|
||||
<h2>{$lang->file_name}</h2>
|
||||
<form action="./" method="post" class="x_form-horizontal">
|
||||
<input type="hidden" name="module" value="file" />
|
||||
<input type="hidden" name="act" value="procFileAdminEditFileName" />
|
||||
<input type="hidden" name="xe_validator_id" value="modules/file/tpl/edit/1" />
|
||||
<input type="hidden" name="file_srl" value="{$file->file_srl}" />
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label" for="file_name">{$lang->file_name}</label>
|
||||
<div class="x_controls">
|
||||
<input type="text" name="file_name" id="file_name" value="{$file->source_filename}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="x_clearfix btnArea">
|
||||
<div class="x_pull-right">
|
||||
<button type="submit" class="x_btn x_btn-primary">{$lang->cmd_save}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<!--@if(preg_match('/\.(gif|jpe?g|png|bmp|webp|heic|avif)$/i', $file->source_filename, $matches))-->
|
||||
<!--@if(!$file->width || !$file->height)-->
|
||||
{@ list($file->width, $file->height) = getimagesize($file->uploaded_filename)}
|
||||
<!--@endif-->
|
||||
{@ $extension = strtolower($matches[1]); if ($extension === 'jpeg') $extension = 'jpg'; }
|
||||
<section class="section">
|
||||
<h2>{$lang->image_conversion}</h2>
|
||||
<form action="./" method="post" class="x_form-horizontal">
|
||||
<input type="hidden" name="module" value="file" />
|
||||
<input type="hidden" name="act" value="procFileAdminEditImage" />
|
||||
<input type="hidden" name="xe_validator_id" value="modules/file/tpl/edit/2" />
|
||||
<input type="hidden" name="file_srl" value="{$file->file_srl}" />
|
||||
<input type="hidden" name="original_width" value="{$file->width}" />
|
||||
<input type="hidden" name="original_height" value="{$file->height}" />
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label">{$lang->image_size}</label>
|
||||
<div class="x_controls">
|
||||
<input type="number" name="new_width" id="new_width" value="{$file->width}" /> x
|
||||
<input type="number" name="new_height" id="new_height" value="{$file->height}" />
|
||||
<p class="x_help-block">
|
||||
<button type="button" class="preset_size">2560</button>
|
||||
<button type="button" class="preset_size">1920</button>
|
||||
<button type="button" class="preset_size">1440</button>
|
||||
<button type="button" class="preset_size">1280</button>
|
||||
<button type="button" class="preset_size">1024</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label" for="format">{$lang->image_format}</label>
|
||||
<div class="x_controls">
|
||||
<select name="format" id="format">
|
||||
<option value="jpg" selected="selected"|cond="$extension === 'jpg'">JPG</option>
|
||||
<option value="png" selected="selected"|cond="$extension === 'png'">PNG</option>
|
||||
<option value="webp" selected="selected"|cond="$extension === 'webp'">WebP</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label" for="quality">{$lang->image_quality}</label>
|
||||
<div class="x_controls">
|
||||
<input type="number" min="50" max="100" name="quality" id="quality" value="{$config->image_quality_adjustment ?? 75}" /> %
|
||||
</div>
|
||||
</div>
|
||||
<div class="x_clearfix btnArea">
|
||||
<div class="x_pull-right">
|
||||
<button type="submit" class="x_btn x_btn-primary">{$lang->cmd_save}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
<!--@endif-->
|
||||
|
|
@ -50,6 +50,7 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
|
|||
</th>
|
||||
<th scope="col" class="nowr">{$lang->ipaddress}</th>
|
||||
<th scope="col" class="nowr">{$lang->status}</th>
|
||||
<th scope="col" class="nowr">{$lang->cmd_edit}</th>
|
||||
<th scope="col"><input type="checkbox" data-name="cart" title="Check All" /></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -66,7 +67,7 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
|
|||
<!--@end-->
|
||||
{@ $cur_upload_target_srl = $val->upload_target_srl}
|
||||
<tr>
|
||||
<th colspan="8" scope="col">
|
||||
<th colspan="9" scope="col">
|
||||
<!--@if(!$val->upload_target_type)-->
|
||||
<!--@if($val->isvalid=='Y')-->
|
||||
{$lang->is_valid}
|
||||
|
|
@ -112,6 +113,9 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
|
|||
<td class="nowr">{zdate($val->regdate,"Y-m-d H:i")}</td>
|
||||
<td class="nowr"><a href="{getUrl('search_target','ipaddress','search_keyword',$val->ipaddress)}">{$val->ipaddress}</a></td>
|
||||
<td class="nowr"><!--@if($val->isvalid=='Y')-->{$lang->is_valid}<!--@else-->{$lang->is_stand_by}<!--@end--></td>
|
||||
<td class="nowr">
|
||||
<a href="{getUrl(['module' => 'admin', 'act' => 'dispFileAdminEdit', 'file_srl' => $val->file_srl])}">{$lang->cmd_edit}</a>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="cart" value="{$val->file_srl}" />
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
<load target="css/config.css" />
|
||||
<load target="js/file_admin.js" />
|
||||
|
||||
<div class="x_page-header">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ function getFileList() {
|
|||
var fileListTable = jQuery('#fileListTable');
|
||||
var cartList = [];
|
||||
fileListTable.find(':checkbox[name=cart]').each(function(){
|
||||
if(this.checked) cartList.push(this.value);
|
||||
if(this.checked) cartList.push(this.value);
|
||||
});
|
||||
|
||||
var params = new Array();
|
||||
|
|
@ -58,3 +58,24 @@ function checkSearch(form)
|
|||
}
|
||||
*/
|
||||
}
|
||||
|
||||
(function() {
|
||||
$(function() {
|
||||
$('.preset_size').on('click', function() {
|
||||
const preset_size = parseInt($(this).text(), 10);
|
||||
const width = parseInt($('input[name=original_width]').val(), 10);
|
||||
const height = parseInt($('input[name=original_height]').val(), 10);
|
||||
let new_width = 0;
|
||||
let new_height = 0;
|
||||
if (width > height) {
|
||||
new_width = preset_size;
|
||||
new_height = Math.round(preset_size * (height / width));
|
||||
} else {
|
||||
new_width = Math.round(preset_size * (width / height));
|
||||
new_height = preset_size;
|
||||
}
|
||||
$('input[name=new_width]').val(new_width);
|
||||
$('input[name=new_height]').val(new_height);
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue