summaryrefslogblamecommitdiffstats
path: root/modules-available/sysconfig/addmodule_branding.inc.php
blob: 54b2ad5773ea027566e8adc0d35d5be8e39cc49e (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11





                                        




                                           
                                                                                                                               
                                                         
                                                                                 









                                                 




                                                                                                                           
                                                              

















                                                                                                                      
                                       

                                                                                               
                                                                                                     
                         
                                                          

                                            
                                                                            
                                                                             
                                                      

                                                           
                                                                           




                                                                                             
                                                   








                                                                                                
                                                                                                                               

                                      
                                                                                             
                                                    

                                                                                      





                                        
                                                                                                             



                                                                                      
                                                                                                                            

                                        
                                                                                        
         
                               
                                            



                                                                                                            




                                                                                                        
                                                                        




                                                                                                                        



                                                                                                                                                                            
                                                                                                                   
                                                                                                      

                                             













                                                                                                   

                                                                                  
                                                                                                                                             

                                                          
                                 
                                                                    
                                              
                                                         




                                            
                                              
                             








                                                                                         
                                                                                              




                                          

                                                 
 

                                                 
                                                                       

















                                                                        





                                                              

                                    

                                                      











                                                
                                  
                                                           
                                    
                                                                                                                 



                                                                                             
                                                                   

                                                                                             
                                           
                                                                        
                        
                                              
                 
                                                  
                                         
                                                       


                                                       
                                                                                             
                                                                                     

                                                                                             
                                                 
                      
                                           
                                                             
                        
                                                            


                                                                                   



                                                
<?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');
	}

}