JENS MALMGREN I create, that is my hobby.

Porting my blog for the second time, editing part 5

This is post #50 of my series about how I port this blog from Blogengine.NET 2.5 ASPX on a Windows Server 2003 to a Linux Ubuntu server, Apache2, MySQL and PHP. A so called LAMP. The introduction to this project can be found in this blog post https://www.malmgren.nl/post/Porting-my-blog-for-the-second-time-Project-can-start.aspx.

Part 5 of editing at post 50 started on 25 April! Well... Starting writing a post is one thing but when will it be finished? Sometime in May?

Anyway... We were at how to uploading huge images and automatically resize them to something quicker to load and easier to view on a smartphone.

By now I know the drill. Make up a clever search in Google, such as "resize image php code" and then read a bit about it and then refine the search to "php imagecreatefromjpeg" and finally get to this page: http://php.net/manual/en/function.imagecreatefromjpeg.php where I decided to try the solution provided by juozaspo.

So for this a made a new php program to try out the concept.

Reading the source I figured I could call it as following to test it:

http://jenstestblog.nl/testresize.php?url=media/testimage.JPG&w=100

This here above is just an example. But it did not work. The log file of Apache revealed:

PHP Fatal error:  Call to undefined function imagecreatefromjpeg()

You need to install php-gd obviously! Right? no I missed that.

This was supposed to be the solution: # apt-get install php5-gd

Processing triggers for man-db (2.6.7.1-1ubuntu1) ...
E: Failed to fetch http://security.ubuntu.com/ubuntu/pool/main/p/php5/php5-gd_5.5.9+dfsg-1ubuntu4.14_amd64.deb  404  Not Found [IP: 2001:67c:1360:8001::17 80]

Hmm...

There is luckily a page for everything: http://ubuntuforums.org/archive/index.php/t-1047929.html

So I ran apt-get update and then apt-get php5-gd and this time it looked more promising:

root@server:/home/jmalmgre# apt-get install php5-gd
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
  linux-headers-3.19.0-25 linux-headers-3.19.0-25-generic
  linux-image-3.19.0-25-generic linux-image-extra-3.19.0-25-generic
  linux-signed-image-3.19.0-25-generic
Use 'apt-get autoremove' to remove them.
The following extra packages will be installed:
  libapache2-mod-php5 php5-cli php5-common php5-mysql php5-readline
Suggested packages:
  php-pear php5-user-cache
The following NEW packages will be installed:
  php5-gd
The following packages will be upgraded:
  libapache2-mod-php5 php5-cli php5-common php5-mysql php5-readline
5 upgraded, 1 newly installed, 0 to remove and 121 not upgraded.
8 not fully installed or removed.
Need to get 4,918 kB of archives.
After this operation, 164 kB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 http://nl.archive.ubuntu.com/ubuntu/ trusty-updates/main php5-mysql amd64 5.5.9+dfsg-1ubuntu4.16 [62.9 kB]
Get:2 http://nl.archive.ubuntu.com/ubuntu/ trusty-updates/main php5-readline amd64 5.5.9+dfsg-1ubuntu4.16 [12.1 kB]
Get:3 http://nl.archive.ubuntu.com/ubuntu/ trusty-updates/main php5-cli amd64 5.5.9+dfsg-1ubuntu4.16 [2,164 kB]
Get:4 http://nl.archive.ubuntu.com/ubuntu/ trusty-updates/main libapache2-mod-php5 amd64 5.5.9+dfsg-1ubuntu4.16 [2,207 kB]
Get:5 http://nl.archive.ubuntu.com/ubuntu/ trusty-updates/main php5-common amd64 5.5.9+dfsg-1ubuntu4.16 [445 kB]
Get:6 http://nl.archive.ubuntu.com/ubuntu/ trusty-updates/main php5-gd amd64 5.5.9+dfsg-1ubuntu4.16 [27.8 kB]
Fetched 4,918 kB in 1s (3,492 kB/s)
(Reading database ... 124331 files and directories currently installed.)
Preparing to unpack .../php5-mysql_5.5.9+dfsg-1ubuntu4.16_amd64.deb ...
Unpacking php5-mysql (5.5.9+dfsg-1ubuntu4.16) over (5.5.9+dfsg-1ubuntu4.14) ...
Preparing to unpack .../php5-readline_5.5.9+dfsg-1ubuntu4.16_amd64.deb ...
Unpacking php5-readline (5.5.9+dfsg-1ubuntu4.16) over (5.5.9+dfsg-1ubuntu4.14) ...
Preparing to unpack .../php5-cli_5.5.9+dfsg-1ubuntu4.16_amd64.deb ...
Unpacking php5-cli (5.5.9+dfsg-1ubuntu4.16) over (5.5.9+dfsg-1ubuntu4.14) ...
Preparing to unpack .../libapache2-mod-php5_5.5.9+dfsg-1ubuntu4.16_amd64.deb ...
Unpacking libapache2-mod-php5 (5.5.9+dfsg-1ubuntu4.16) over (5.5.9+dfsg-1ubuntu4.14) ...
Preparing to unpack .../php5-common_5.5.9+dfsg-1ubuntu4.16_amd64.deb ...
Unpacking php5-common (5.5.9+dfsg-1ubuntu4.16) over (5.5.9+dfsg-1ubuntu4.14) ...
Selecting previously unselected package php5-gd.
Preparing to unpack .../php5-gd_5.5.9+dfsg-1ubuntu4.16_amd64.deb ...
Unpacking php5-gd (5.5.9+dfsg-1ubuntu4.16) ...
Processing triggers for man-db (2.6.7.1-1ubuntu1) ...
Setting up fonts-dejavu-core (2.34-1ubuntu1) ...
Setting up fontconfig-config (2.11.0-0ubuntu4.1) ...
Setting up libfontconfig1:amd64 (2.11.0-0ubuntu4.1) ...
Setting up libjbig0:amd64 (2.0-2ubuntu4.1) ...
Setting up libtiff5:amd64 (4.0.3-7ubuntu0.4) ...
Setting up libvpx1:amd64 (1.3.0-2) ...
Setting up libxpm4:amd64 (1:3.5.10-1) ...
Setting up libgd3:amd64 (2.1.0-3) ...
Setting up php5-common (5.5.9+dfsg-1ubuntu4.16) ...
php5_invoke pdo: already enabled for apache2 SAPI
php5_invoke pdo: already enabled for cli SAPI
php5_invoke opcache: already enabled for apache2 SAPI
php5_invoke opcache: already enabled for cli SAPI
Setting up php5-mysql (5.5.9+dfsg-1ubuntu4.16) ...
php5_invoke mysql: already enabled for apache2 SAPI
php5_invoke mysql: already enabled for cli SAPI
php5_invoke mysqli: already enabled for apache2 SAPI
php5_invoke mysqli: already enabled for cli SAPI
php5_invoke pdo_mysql: already enabled for apache2 SAPI
php5_invoke pdo_mysql: already enabled for cli SAPI
Setting up php5-cli (5.5.9+dfsg-1ubuntu4.16) ...
php5_invoke mysqli: already enabled for cli SAPI
php5_invoke pdo: already enabled for cli SAPI
php5_invoke json: already enabled for cli SAPI
php5_invoke readline: already enabled for cli SAPI
php5_invoke opcache: already enabled for cli SAPI
php5_invoke mysql: already enabled for cli SAPI
php5_invoke pdo_mysql: already enabled for cli SAPI
Setting up php5-readline (5.5.9+dfsg-1ubuntu4.16) ...
php5_invoke readline: already enabled for apache2 SAPI
php5_invoke readline: already enabled for cli SAPI
Setting up libapache2-mod-php5 (5.5.9+dfsg-1ubuntu4.16) ...
php5_invoke mysqli: already enabled for apache2 SAPI
php5_invoke pdo: already enabled for apache2 SAPI
php5_invoke json: already enabled for apache2 SAPI
php5_invoke readline: already enabled for apache2 SAPI
php5_invoke opcache: already enabled for apache2 SAPI
php5_invoke mysql: already enabled for apache2 SAPI
php5_invoke pdo_mysql: already enabled for apache2 SAPI
apache2_invoke php5: already enabled
 * Restarting web server apache2                                                                                                 [ OK ]
Setting up php5-gd (5.5.9+dfsg-1ubuntu4.16) ...

Creating config file /etc/php5/mods-available/gd.ini with new version
php5_invoke: Enable module gd for apache2 SAPI
php5_invoke: Enable module gd for cli SAPI
Processing triggers for libc-bin (2.19-0ubuntu6.7) ...
Processing triggers for libapache2-mod-php5 (5.5.9+dfsg-1ubuntu4.16) ...

So now I have gd installed. Will it help? Noo...

When searchning for "php imagecreatefromjpeg undefined function" I found this https://www.tectut.com/2015/10/solved-call-to-undefined-function-imagecreatefromjpeg/

Hmm...

Skipped (2) but I did (1) and (3). YES! Now we are getting somewhere:

Is it working?

Yes. It is working.

But this is not what I need. What I need is that after upload the uploaded file will get resized. So to do that I create this little test program:

≺?php
$ip_strFullPathToImage = "/var/www/jensblog/public_html/media/swedish.jpg";
$newFile = ResizeImageAndReturnFullPathOfNewImage($ip_strFullPathToImage, 200, null);
echo "New resized image: " . $newFile . "≺br≻";

function OpenImage($ip_strFullPathToImage)
{
	$type=false;
	$size=getimagesize($ip_strFullPathToImage);
	switch($size["mime"])
	{
		case "image/jpeg":
			$image = imageCreateFromJpeg($ip_strFullPathToImage);
			break;
		case "image/gif":
			$image = imagecreatefromgif($ip_strFullPathToImage);
			break;
		case "image/png":
			$image = imagecreatefrompng($ip_strFullPathToImage);
			break;
		default:
			$image=false;
			break;
    }
    return $image;
} // OpenImage()


function ResizeImageAndReturnFullPathOfNewImage($ip_strFullPathToImage, $ip_iNewWidthOrNull, $ip_iNewHeightOrNull)
{
	$image = OpenImage($ip_strFullPathToImage);
	if ($image === false) { die ('Unable to open image'); }
	$w = imagesx($image);
	$h = imagesy($image);

	if (isset($ip_iNewWidthOrNull) && !isset($ip_iNewHeightOrNull))
	{
		$ip_iNewHeightOrNull = $ip_iNewWidthOrNull * ($h / $w);
	}
	else if (!isset($ip_iNewWidthOrNull) && isset($ip_iNewHeightOrNull))
	{
		$ip_iNewWidthOrNull = $ip_iNewHeightOrNull * ($w/$h);
	}
	else
	{
		$ip_iNewWidthOrNull = isset($ip_iNewWidthOrNull) ? $ip_iNewWidthOrNull : 500;
		$ip_iNewHeightOrNull = isset($ip_iNewHeightOrNull) ? $ip_iNewHeightOrNull : 500;
		if (($w/$h) ≻ ($ip_iNewWidthOrNull/$ip_iNewHeightOrNull))
		{
			$ip_iNewHeightOrNull = $ip_iNewWidthOrNull * ($h/$w);
		} else {
			$ip_iNewWidthOrNull = $ip_iNewHeightOrNull * ($w/$h);   
		}
	}

	$image2 = ImageCreateTrueColor($ip_iNewWidthOrNull, $ip_iNewHeightOrNull);
	imagecopyResampled ($image2, $image, 0, 0, 0, 0, $ip_iNewWidthOrNull, $ip_iNewHeightOrNull, $w, $h);
	$_strFilenameWithExtension = basename($ip_strFullPathToImage);
	$_rootPathEndsWithSlash = dirname($ip_strFullPathToImage) . "/";
	$_iDotPos = strrpos($_strFilenameWithExtension, '.');

	if ($_iDotPos === false)
	{
		$_strBaseName = $_strFilenameWithExtension;
		$_strExtensionStartWithDot = "";
	}
	else
	{
		$_strBaseName = substr($_strFilenameWithExtension, 0, $_iDotPos);
		$_strExtensionStartWithDot = substr($_strFilenameWithExtension, $_iDotPos);
	}
	$_strNewUniqueFilename = GetUniqueFilename($_rootPathEndsWithSlash, $_strFilenameWithExtension, $_strExtensionStartWithDot, 0);
	imagejpeg($image2, $_rootPathEndsWithSlash . $_strNewUniqueFilename);
	return $_rootPathEndsWithSlash . $_strNewUniqueFilename;
} // ResizeImageAndReturnFullPathOfNewImage()

function GetUniqueFilename($ip_strRootEndsWithSlash, $ip_strFileNameWithExtension, $ip_strExtensionStartWithDot, $ip_iCount)
{
	if(file_exists($ip_strRootEndsWithSlash . $ip_strFileNameWithExtension))
	{
		$_strBaseName = preg_replace('/([^_]+?)(_[0-9]+)?\..+?$/i', '$1', $ip_strFileNameWithExtension);
		return GetUniqueFilename($ip_strRootEndsWithSlash, $_strBaseName .'_'. ($ip_iCount +1) . $ip_strExtensionStartWithDot, $ip_strExtensionStartWithDot, ($ip_iCount + 1));
	}
	else
	{
		return $ip_strFileNameWithExtension;
	}
} // GetUniqueFilename()
?≻

So now I need to integrate this solution into the upload functionality in CKEditor. So first of all I need to get to that part of CKEditor creating hyperlink and img tag somehow to display the image. It feels like a huge task so I am back at reading CKEditor documentation. I decided that this page is at the core of what I want to achieve: http://docs.ckeditor.com/#!/guide/dev_file_browser_api

It was especially example 3 that got my attention. The alt field? What alt field? Here it is and it is called "Alternative Text":

I had totally missed the alternative text field in the Image Properties dialog. What else do we have here? The link tab:

There is a link tab with it a field url and target. So I fill in this and try it. Here is the source code produced:

≺a href="test link" target="_blank"≻≺img alt="" src="https://www.malmgren.nl/post/?" style="height:2048px; width:1152px" /≻≺/a≻

That is exactly what I want. Can I set this automatically?

If so then I can make the image url the downsized image and the link url can be the original image. While at it I can set other fields as I like to have them such as margin etc. Wonderful!

How am I going to find out how to get to those fields? With help of CKEditor dev-tools. http://docs.ckeditor.com/#!/guide/dev_devtools So on with it. Went to the download site of CKEditor, enabled the dev-tools plugin and downloaded the whole chabang with dev-tools included. Found out I have to configure it as well:

≺script type = "text/javascript"≻
	CKEDITOR.replace( 'myEditor', {
			uiColor: '#9AB8F3',
			height: 160,
			filebrowserBrowseUrl: '/imgbrowse.php?type=Files',
			filebrowserUploadUrl: '/iaupload.php?type=Files',
			extraPlugins: 'devtools'
	});
≺/script≻

So that was nice but I have not got a bit closer. I want to set those things! Grmbl...

$jensFunc =
"function()
{
	var dialog = this.getDialog();
	/*if ( dialog.getName() == 'image' )*/ {
		var element = dialog.getContentElement( 'info', 'txtAlt' );
		if ( element )
		{
			element.setValue( 'alt text' );
		}
	}
	return true;
}";

$re = "window.parent.CKEDITOR.tools.callFunction($CKEditorFuncNum, '$url', $jensFunc)";

Here above is my sample. This text is echoed to CKEditor when the file is being submitted. I had the sample copied from the documentation so it should be fine. I was sitting here after some time wondering about the check if the dialog was named 'image'. If that failed somehow then nothing would happen and that is my situation. So if I removed it.

IT WORKED!!!

So now I have my proof of concept. No I am not worried that I don't check the name of the dialog. If that fails then I work on that another time.

But it is not working for bigger files. For that I had to add these two lines to the .htaccess file

php_value upload_max_filesize 10M
php_value post_max_size 10M

But that only made the image to upload and the smaller version to be created. The dialog would not work entirely. Hmm...

Ooh, obviously! I entered the path to the image for on the local system but not the URL for the image as it should be seen from the webserver!

When corrected that it worked! The image information was set correctly. The small image was displayed and the big image was linked to - in one operation!

Here is the complete upload program doing the resize etc:

≺?php
// PHP Upload Script for CKEditor:  http://coursesweb.net/

// HERE SET THE PATH TO THE FOLDERS FOR IMAGES AND AUDIO ON YOUR SERVER (RELATIVE TO THE ROOT OF YOUR WEBSITE ON SERVER)
$upload_dir = array(
	'img'=≻ '/media/',
	'audio'=≻ '/media/'
);

// HERE PERMISSIONS FOR IMAGE
$imgset = array(
	'maxsize' =≻ 10000,     // maximum file size, in KiloBytes (2 MB)
	'maxwidth' =≻ 5000,     // maximum allowed width, in pixels
	'maxheight' =≻ 5000,    // maximum allowed height, in pixels
	'minwidth' =≻ 10,      // minimum allowed width, in pixels
	'minheight' =≻ 10,     // minimum allowed height, in pixels
	'type' =≻ array('bmp', 'gif', 'jpg', 'jpe', 'png'),  // allowed extensions
);

// HERE PERMISSIONS FOR AUDIO
$audioset = array(
	'maxsize' =≻ 20000,    // maximum file size, in KiloBytes (20 MB)
	'type' =≻ array('mp3', 'ogg', 'wav'),  // allowed extensions
);

// If 1 and filename exists, RENAME file, adding "_NR" to the end of filename (name_1.ext, name_2.ext, ..)
// If 0, will OVERWRITE the existing file
define('RENAME_F', 0);

$re = '';
if(isset($_FILES['upload']) && strlen($_FILES['upload']['name']) ≻1)
{
	define('F_NAME', preg_replace('/\.(.+?)$/i', '', basename($_FILES['upload']['name'])));

	$protocol = !empty($_SERVER['HTTPS']) ? 'https://' : 'http://';
	$site = $protocol. $_SERVER['SERVER_NAME'] .'/';
	$sepext = explode('.', strtolower($_FILES['upload']['name']));
	$type = end($sepext);    // gets extension
	$upload_dir = in_array($type, $imgset['type']) ? $upload_dir['img'] : $upload_dir['audio'];
	$upload_dir = trim($upload_dir, '/') .'/';

	if(in_array($type, $imgset['type']))
	{
		list($width, $height) = getimagesize($_FILES['upload']['tmp_name']);  // image width and height
		if(isset($width) && isset($height))
		{
			if($width ≻ $imgset['maxwidth'] || $height ≻ $imgset['maxheight'])
			{
				$re .= '\\n Width x Height = '. $width .' x '. $height .' \\n The maximum Width x Height must be: '. $imgset['maxwidth']. ' x '. $imgset['maxheight'];
			}
			if($width ≺ $imgset['minwidth'] || $height ≺ $imgset['minheight'])
			{
				$re .= '\\n Width x Height = '. $width .' x '. $height .'\\n The minimum Width x Height must be: '. $imgset['minwidth']. ' x '. $imgset['minheight'];
			}
			if($_FILES['upload']['size'] ≻ $imgset['maxsize']*1000)
			{
				$re .= '\\n Maximum file size must be: '. $imgset['maxsize']. ' KB.';
			}
		}
	}
	else if(in_array($type, $audioset['type']))
	{
		if($_FILES['upload']['size'] ≻ $audioset['maxsize']*1000) $re .= '\\n Maximum file size must be: '. $audioset['maxsize']. ' KB.';
	}
	else
	{
		$re .= 'The file: '. $_FILES['upload']['name']. ' has not the allowed extension type.';
	}

	//set filename; if file exists, and RENAME_F is 1, set "img_name_I"
	// $p = dir-path, $fn=filename to check, $ex=extension $i=index to rename
	function setFName($p, $fn, $ex, $i)
	{
		if(RENAME_F ==1 && file_exists($p .$fn .$ex))
		{
			return setFName($p, F_NAME .'_'. ($i +1), $ex, ($i +1));
		}
		else
		{
			return $fn .$ex;
		}
	}

	$f_name = setFName($_SERVER['DOCUMENT_ROOT'] .'/'. $upload_dir, F_NAME, ".$type", 0);
	$uploadpath = $_SERVER['DOCUMENT_ROOT'] .'/'. $upload_dir . $f_name;  // full file path

	// If no errors, upload the image, else, output the errors
	if($re == '')
	{
		if(move_uploaded_file($_FILES['upload']['tmp_name'], $uploadpath))
		{
			$CKEditorFuncNum = $_GET['CKEditorFuncNum'];
			$fullpath = "/var/www/jensblog/public_html/" . $upload_dir . $f_name;
			$url = str_replace("/var/www/jensblog/public_html/", $site, $fullpath);
			$fullpath_small = ResizeImageAndReturnFullPathOfNewImage($fullpath, 200, null);
			$url_small = str_replace("/var/www/jensblog/public_html/", $site, $fullpath_small);
			$msg = F_NAME .'.'. $type .' successfully uploaded: \\n- Size: '. number_format($_FILES['upload']['size']/1024, 2, '.', '') .' KB';

			if (in_array($type, $imgset['type']))
			{
				$jensFunc =
					"function()
					{
					var dialog = this.getDialog();
					dialog.getContentElement( 'Link', 'txtUrl' ).setValue( '$url' );
					dialog.getContentElement( 'Link', 'cmbTarget' ).setValue( '_blank' );
					dialog.getContentElement( 'info', 'txtHSpace' ).setValue( '5' );
					dialog.getContentElement( 'info', 'txtVSpace' ).setValue( '5' );
					return true;
					}";
				$re = "window.parent.CKEDITOR.tools.callFunction($CKEditorFuncNum, '$url_small', $jensFunc)";
			}
			else
			{
				$re = 'var cke_ob = window.parent.CKEDITOR; for(var ckid in cke_ob.instances) { if(cke_ob.instances[ckid].focusManager.hasFocus) break;} cke_ob.instances[ckid].insertHtml(\'≺audio src="'. $url .'" controls≻≺/audio≻\', \'unfiltered_html\'); alert("'. $msg .'"); var dialog = cke_ob.dialog.getCurrent();  dialog.hide();';
			}
		}
		else
		{
			$re = 'alert("Unable to upload the file")';
		}
	}
	else
	{
		$re = 'alert("'. $re .'")';
	}
}


function OpenImage($ip_strFullPathToImage)
{
	$type=false;
	$size=getimagesize($ip_strFullPathToImage);
	switch($size["mime"])
	{
		case "image/jpeg":
			$image = imageCreateFromJpeg($ip_strFullPathToImage);
			break;
		case "image/gif":
			$image = imagecreatefromgif($ip_strFullPathToImage);
			break;
		case "image/png":
			$image = imagecreatefrompng($ip_strFullPathToImage);
			break;
		default:
			$image=false;
			break;
    }
    return $image;
} // OpenImage()

function ResizeImageAndReturnFullPathOfNewImage($ip_strFullPathToImage, $ip_iNewWidthOrNull, $ip_iNewHeightOrNull)
{
	$image = OpenImage($ip_strFullPathToImage);
	if ($image === false) { die ('Unable to open image'); }
	$w = imagesx($image);
	$h = imagesy($image);

	if (isset($ip_iNewWidthOrNull) && !isset($ip_iNewHeightOrNull))
	{
		$ip_iNewHeightOrNull = $ip_iNewWidthOrNull * ($h / $w);
	}
	else if (!isset($ip_iNewWidthOrNull) && isset($ip_iNewHeightOrNull))
	{
		$ip_iNewWidthOrNull = $ip_iNewHeightOrNull * ($w/$h);
	}
	else
	{
		$ip_iNewWidthOrNull = isset($ip_iNewWidthOrNull) ? $ip_iNewWidthOrNull : 500;
		$ip_iNewHeightOrNull = isset($ip_iNewHeightOrNull) ? $ip_iNewHeightOrNull : 500;
		if (($w/$h) ≻ ($ip_iNewWidthOrNull/$ip_iNewHeightOrNull))
		{
			$ip_iNewHeightOrNull = $ip_iNewWidthOrNull * ($h/$w);
		} else {
			$ip_iNewWidthOrNull = $ip_iNewHeightOrNull * ($w/$h);   
		}
	}

	$image2 = ImageCreateTrueColor($ip_iNewWidthOrNull, $ip_iNewHeightOrNull);
	imagecopyResampled ($image2, $image, 0, 0, 0, 0, $ip_iNewWidthOrNull, $ip_iNewHeightOrNull, $w, $h);
	$_strFilenameWithExtension = basename($ip_strFullPathToImage);
	$_rootPathEndsWithSlash = dirname($ip_strFullPathToImage) . "/";
	$_iDotPos = strrpos($_strFilenameWithExtension, '.');

	if ($_iDotPos === false)
	{
		$_strBaseName = $_strFilenameWithExtension;
		$_strExtensionStartWithDot = "";
	}
	else
	{
		$_strBaseName = substr($_strFilenameWithExtension, 0, $_iDotPos);
		$_strExtensionStartWithDot = substr($_strFilenameWithExtension, $_iDotPos);
	}
	$_strNewUniqueFilename = GetUniqueFilename($_rootPathEndsWithSlash, $_strFilenameWithExtension, $_strExtensionStartWithDot, 0);
	imagejpeg($image2, $_rootPathEndsWithSlash . $_strNewUniqueFilename);
	return $_rootPathEndsWithSlash . $_strNewUniqueFilename;
} // ResizeImageAndReturnFullPathOfNewImage()

function GetUniqueFilename($ip_strRootEndsWithSlash, $ip_strFileNameWithExtension, $ip_strExtensionStartWithDot, $ip_iCount)
{
	if(file_exists($ip_strRootEndsWithSlash . $ip_strFileNameWithExtension))
	{
		$_strBaseName = preg_replace('/([^~]+?)(~[0-9]+)?\..+?$/i', '$1', $ip_strFileNameWithExtension);
		return GetUniqueFilename($ip_strRootEndsWithSlash, $_strBaseName .'~'. ($ip_iCount +1) . $ip_strExtensionStartWithDot, $ip_strExtensionStartWithDot, ($ip_iCount + 1));
	}
	else
	{
		return $ip_strFileNameWithExtension;
	}
} // GetUniqueFilename()


@header('Content-type: text/html; charset=utf-8');
echo '≺script≻'. $re .';≺/script≻';

If you use this you would not use my paths obviously.

This concludes the upload.

But wait! Is it working? The resizing is not working properly. When the rendered blog-page becomes so narrow that the image should be squezed with preserved aspect ratio instead it just got narrower while the height stayed the same. The problem is caused by that the height and width is provided in the style by CKEditor and not as width and height attributes, baffling - I know. Without width and height in the style and instead as attributes then together with this style here below then liquid design resizing with preserved aspect ratio works properly:

#contentcolumn img
{
	max-width : 100%;
	height: auto;
}

But how should I solve that? I will have to strip out the width and height if they are provided in the style and then add the missing attributes. So I did that in the ParseContentEncodeImages:

≺?php

function ParseContentEncodeImages($ip_strSlug, $ip_strContent)
{
	global $mysqli;
	global $debug;
	
	preg_match_all("/(≺a.+?≻|≺img.+?\/≻)/", $ip_strContent, $matches, PREG_OFFSET_CAPTURE );
	$matches_terms = $matches[1];
	
	for ($i = count($matches_terms) - 1; $i ≻= 0; $i--)
	{
		$match_term_position = $matches_terms[$i];
		$match_term = $match_term_position[0];
		$match_position = $match_term_position[1];
		
		// Parse width from either style or attribute
		$_strWidth = "";
		if (preg_match("/[\s\"']width\s*[=:]\s*['\"]?([0-9]+)/i", $match_term, $match))
		{
			$_strWidth = $match[1];
		}
		// Parse height from either style or attribute
		$_strHeight = "";
		if (preg_match("/[\s\"']height\s*[=:]\s*['\"]?([0-9]+)/i", $match_term, $match))
		{
			$_strHeight = $match[1];
		}
		
		// Find out if width originates from attribute
		$_strWidthAttribute = "";
		if (preg_match("/width\s*=\s*['\"]([0-9]+)[\'\"]/i", $match_term, $match))
		{
			$_strWidthAttribute = $match[1];
		}
		// Find out if height originates from attribute
		$_strHeightAttribute = "";
		if (preg_match("/height\s*=\s*['\"]([0-9]+)[\'\"]/i", $match_term, $match))
		{
			$_strHeightAttribute = $match[1];
		}

		// Parse the whole style
		$_strStyle = "";
		// If the style contains width or height then these are removed
		$_strNewStyle = "";
		if (preg_match("/style\s*=\s*['\"](.+?)['\"]/i", $match_term, $match))
		{
			$_strStyle = $match[1];
			$_strNewStyle = preg_replace("/^(.*?)\s*width\s*:[0-9]+\s*px;?\s*(.*?)$/i", "$1 $2", $_strStyle);
			$_strNewStyle = preg_replace("/^(.*?)\s*height\s*:[0-9]+\s*px;?\s*(.*?)$/i", "$1 $2", $_strNewStyle);
		}
		$_strTag = "";
		if (preg_match("/≺([a-z]+)/i", $match_term, $match))
		{
			$_strTag = $match[1];
		}
		$_strURL = "";
		if (preg_match("/(href|src)\s*=\s*['\"](.+?)['\"]/i", $match_term, $match))
		{
			$_strURL = $match[2];
		}
		$_strFileName = "";
		$_strID = "";
		if (preg_match("/media\/(.+?)$/i", $_strURL, $match))
		{
			$_strFileName = $match[1];
			$query = GetQueryWithData(1, "select ID from URL where FileName = ?", $_strFileName);
			$result = $mysqli-≻query($query) or die("Error query.." . mysqli_error($mysqli));
			if ($row = mysqli_fetch_array($result))
			{
				// Available in the database already.
				$_strID = $row['ID'];
			}
			else
			{
				// Media was not available. Add it. http://www.jens.malmgren.nl/post/Porting-my-blog-for-the-second-time-editing-part-4.aspx
				$query = GetQueryWithData(0,
					"INSERT INTO URL (	TagName,	Width,		Height,			IsLocalURL,	Style,		IsFileContent, 	FileName  )" .
					"VALUES 		 (	?,			?,			?,				?,			?,			?, 				?         )",
					$_strTag,	$_strWidth,	$_strHeight,	1,			$_strStyle,	1,				$_strFileName);
				$result = $mysqli-≻query($query) or die("Error query.." . mysqli_error($mysqli));
				$_strID = $mysqli-≻insert_id;
				
				$query = GetQueryWithData(1, "INSERT PostURL (PostID, URLID) SELECT Post.ID, ? FROM Post WHERE Post.Slug = ?", $_strID, $ip_strSlug);
				$result = $mysqli-≻query($query) or die("Error query.." . mysqli_error($mysqli));
			}
		}
		
		if ($_strID == "" && preg_match("/\/post\/(.+?)$/i", $_strURL, $match))
		{
			$_strFileName = $match[1] . ".aspx";
			$query = GetQueryWithData(1, "select ID from URL where FileName = ?", $_strFileName);
			$result = $mysqli-≻query($query) or die("Error query.." . mysqli_error($mysqli));
			if ($row = mysqli_fetch_array($result))
			{
				$_strID = $row['ID'];
			}
		}
		
		if ($_strID == "" && preg_match("/(http:\/\/.+?)$/i", $_strURL, $match))
		{
			$_strFileName = $match[1];
			$query = GetQueryWithData(0, "select ID from URL where FileName = ?", $_strFileName);
			$result = $mysqli-≻query($query) or die("Error query.." . mysqli_error($mysqli));
			if ($row = mysqli_fetch_array($result))
			{
				$_strID = $row['ID'];
			}
		}
		
		$_additionalWidthHeight = "";
		
		if ($_strHeight != "" && $_strHeightAttribute == "")
		{
			$_additionalWidthHeight = " height = \"" . $_strHeight . "\" ";
		}
		if ($_strWidth != "" && $_strWidthAttribute == "")
		{
			$_additionalWidthHeight .= " width = \"" . $_strWidth . "\" ";
		}

		$new_match_term = preg_replace("/(href|src)(\s*=\s*['\"])(.+?)(['\"])/", "$1$2{URL:$_strID}$4$_additionalWidthHeight", $match_term);
		// http://www.jens.malmgren.nl/post/Porting-my-blog-for-the-second-time-editing-part-5.aspx
		$new_match_term = str_replace($_strStyle, $_strNewStyle, $new_match_term);
		$ip_strContent = substr_replace($ip_strContent, $new_match_term, $match_position, strlen($match_term));
	}
	return $ip_strContent;
}

?≻

I am not done with the browse functionality and I still have not disabled the paste function that place the image as an ugly base46 encoded chunk in the html source.

But all that is for the future posts!

Started on this on 25 April and finished it on 10 May. Could be worse. I had another holiday inbetween so this is going fine.


I was born 1967 in Stockholm, Sweden. I grew up in the small village Vågdalen in north Sweden. 1989 I moved to Umeå to study Computer Science at University of Umeå. 1995 I moved to the Netherlands where I live in Almere not far from Amsterdam.

Here on this site I let you see my creations.

I create, that is my hobby.