<?php
/*
* Wizard for including a branding logo.
*/
class Branding_Start extends AddModule_Base
{
protected function renderInternal()
{
Render::addDialog(Dictionary::translateFile('config-module', 'branding_title'), false, 'branding-start', array(
'step' => 'Branding_ProcessFile',
'edit' => $this->edit == null ? null : $this->edit->id(),
));
}
}
class Branding_ProcessFile extends AddModule_Base
{
private $task;
private $svgFile;
protected function preprocessInternal()
{
$url = Request::post('url');
if ((!isset($_FILES['file']['error']) || $_FILES['file']['error'] === UPLOAD_ERR_NO_FILE) && empty($url)) {
Message::addError('main.empty-field');
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
$this->svgFile = tempnam(sys_get_temp_dir(), 'bwlp-');
if (isset($_FILES['file']['error']) && $_FILES['file']['error'] !== UPLOAD_ERR_NO_FILE) {
// Prefer uploaded image over URL (in case both are given)
if ($_FILES['file']['error'] !== UPLOAD_ERR_OK) {
Message::addError('upload-failed', Util::uploadErrorString($_FILES['file']['error']));
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
if (!move_uploaded_file($_FILES["file"]["tmp_name"], $this->svgFile)) {
Message::addError('upload-failed', 'Moving temp file failed');
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
} else {
// URL - launch task that fetches the SVG file from it
if (strpos($url, '://') === false)
$url = "http://$url";
$title = false;
if (!Branding_ProcessFile::downloadSvg($this->svgFile, $url, $title)) {
@unlink($this->svgFile);
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
Session::set('logo_name', $title);
}
chmod($this->svgFile, 0644);
$tarFile = '/tmp/bwlp-' . time() . '-' . mt_rand() . '.tgz';
$this->task = Taskmanager::submit('BrandingGenerator', array(
'tarFile' => $tarFile,
'svgFile' => $this->svgFile
));
$this->task = Taskmanager::waitComplete($this->task, 5000);
if (Taskmanager::isFailed($this->task)) {
@unlink($this->svgFile);
Taskmanager::addErrorMessage($this->task);
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
Session::set('logo_tgz', $tarFile);
}
protected function renderInternal()
{
$svg = $png = false;
if (isset($this->task['data']['pngFile']))
$png = base64_encode(file_get_contents($this->task['data']['pngFile']));
if (filesize($this->svgFile) < 1000000)
$svg = base64_encode(file_get_contents($this->svgFile));
Render::addDialog(Dictionary::translateFile('config-module', 'branding_title'), false, 'branding-check', array(
'png' => $png,
'svg' => $svg,
'error' => $this->task['data']['error'] ?? $this->task['statusCode'],
'step' => 'Branding_Finish',
'edit' => $this->edit === null ? null : $this->edit->id(),
'title' => $this->edit === null ? null : $this->edit->title(),
)
);
@unlink($this->svgFile);
}
/**
* Download an svg file from the given url. This function has "wikipedia support", it tries to detect
* URLs in wikipedia articles or thumbnails and then find the actual svg file.
*
* @param string $svgName file to download to
* @param string $url url to download from
* @return boolean true of download succeeded, false on download error (also returns true if downloaded file doesn't
* seem to be svg!)
*/
private static function downloadSvg(string $svgName, string $url, &$title): bool
{
$title = false;
for ($i = 0; $i < 5; ++$i) {
// [wikipedia] Did someone paste a link to a thumbnail of the svg? Let's fix that...
if (preg_match('#^(.*)/thumb/(.*\.svg)/.*\.svg#', $url, $out)) {
$url = $out[1] . '/' . $out[2];
}
$code = 400;
if (!Download::toFile($svgName, $url, 3, $code) || $code < 200 || $code > 299) {
Message::addError('remote-timeout', $url, $code);
return false;
}
$content = FileUtil::readFile($svgName, 250000);
// Is svg file?
if (strpos($content, '<svg') !== false)
return true; // Found an svg tag - don't try to find links to the actual image
// [wikipedia] Try to be nice and detect links that might give a hint where the svg can be found
$out1 = $out2 = $out3 = null;
if (preg_match_all('#href="([^"]*upload.wikimedia.org/[^"]*/[^"]*/[^"]*\.svg)"#', $content, $out1, PREG_PATTERN_ORDER)
|| preg_match_all('#src="([^"]*upload.wikimedia.org/[^"]*/thumb/[^"]*\.svg/[^"]+\.svg[^"]*)"#', $content, $out2, PREG_PATTERN_ORDER)
|| preg_match_all('#href="([^"]+/[^"]+:[^"]+\.svg)"#', $content, $out3, PREG_PATTERN_ORDER)) {
if ($title === false && preg_match('#<title>([^<]*)</title>#i', $content, $tout)) {
$title = trim(preg_replace('/\W*Wikipedia.*/', '', $tout[1]));
}
$new = false;
$out = [];
if (isset($out1[1])) {
$out += $out1[1];
}
if (isset($out2[1])) {
$out += $out2[1];
}
if (isset($out3[1])) {
$out += $out3[1];
}
foreach ($out as $res) {
error_log("Match '$res'");
if (!preg_match('/hochschule|univers|logo|siegel/i', $res))
continue;
if (strpos($res, 'action=edit') !== false)
continue;
$new = Branding_ProcessFile::internetCombineUrl($url, html_entity_decode($res, ENT_COMPAT, 'UTF-8'));
if ($new !== $url)
break;
}
if ($new === $url || $new === false)
break;
error_log("New: '$new'");
$url = $new;
continue;
}
break;
}
Message::addError('no-image');
return false;
}
/**
* Make relative url absolute.
*
* @param string $absolute absolute url to use as base
* @param string $relative relative url that will be converted to an absolute url
* @return string combined absolute url
*/
private static function internetCombineUrl(string $absolute, string $relative): string
{
$p = parse_url($relative);
if (!empty($p["scheme"]))
return $relative;
$parsed = parse_url($absolute);
$path = dirname($parsed['path']);
if ($relative[0] === '/') {
if ($relative[1] === '/')
return "{$parsed['scheme']}:$relative";
$cparts = array_filter(explode("/", $relative));
} else {
$aparts = array_filter(explode("/", $path));
$rparts = array_filter(explode("/", $relative));
$cparts = array_merge($aparts, $rparts);
foreach ($cparts as $i => $part) {
if ($part == '.') {
$cparts[$i] = null;
}
if ($part == '..') {
$cparts[$i - 1] = null;
$cparts[$i] = null;
}
}
$cparts = array_filter($cparts);
}
$path = implode("/", $cparts);
$url = "";
if (!empty($parsed['scheme']))
$url = $parsed['scheme'] . "://";
if (!empty($parsed['user'])) {
$url .= $parsed['user'];
if (!empty($parsed['pass']))
$url .= ":" . $parsed['pass'];
$url .= "@";
}
if ($parsed['host'])
$url .= $parsed['host'] . "/";
$url .= $path;
return $url;
}
}
class Branding_Finish extends AddModule_Base
{
protected function preprocessInternal()
{
$title = Request::post('title');
if (empty($title))
$title = Session::get('logo_name');
if (empty($title)) {
Message::addError('missing-title'); // TODO: Ask for title again instead of starting over
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
$tgz = Session::get('logo_tgz');
if ($tgz === false || !file_exists($tgz)) {
Message::addError('main.error-read', $tgz);
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
if ($this->edit === null) {
$module = ConfigModule::getInstance('Branding');
} else {
$module = $this->edit;
}
$module->setData('tmpFile', $tgz);
if ($this->edit !== null)
$ret = $module->update($title);
else
$ret = $module->insert($title);
if (!$ret)
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
elseif ($module->generate($this->edit === null, NULL, 200) === false)
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
Session::set('logo_tgz', false);
Session::set('logo_name', false);
// Yay
if ($this->edit !== null) {
Message::addSuccess('module-edited');
} else {
Message::addSuccess('module-added');
AddModule_Base::setStep('AddModule_Assign', $module->id());
return;
}
Util::redirect('?do=SysConfig');
}
}