PHP Installer for Web Apps

We all know uploading things via ftp like Squirrel Mail or phpMyAdmin, or any application that has 100′s of small files takes a long time. This is mainly due to the overhead in the commands that have to be preformed to upload each file individually.

The first thing we need to do is to package all of our files into a single large file, this will allow us to massively reduce overhead, since there is only ever one send file command sent. How we do this, is simply add all the files (and the root directory if required) into a zip, so that when they are extracted to the directory on the server, they will appear on the server correctly.

Once we have zipped all of our files up, how do we then expect to be able to unzip them? We need a small bootstrap script (example below) to extract them to the server, which yes, is a second file that is small, but beats having to upload those over few 100 files.

$zip = new ZipArchive();
$r = $zip->open("myzip.zip");
if($r == TRUE) {
  $zip->extractTo("./");
}
$zip->close();

If you now upload and run your bootstrap script, you will notice (if you have the zip extension loaded in PHP) that your zip file has been extracted on the server, and was done a vast amount quicker than it would have taken to upload the individual files.

$package = "myadmin.zip";

$c = file_get_contents($package);

$content = base64_encode($c);
$bcontent = "";

for($i=0; $i<strlen($content); $i+=1024) {
  $c = substr($content, $i, 1024);
  $bcontent .= "\$content .= \"{$c}\";\r\n";
}

$f = fopen("installer.php", "w+");
if($f) {
  fwrite($f, "<?php\r\n");
  fwrite($f, "\$content = \"\";\r\n");
  fwrite($f, $bcontent);
  fwrite($f, "file_put_contents('{$package}', base64_decode(\$content));\r\n");
  fwrite($f, "\$zip = new ZipArchive();\r\n");
  fwrite($f, "\$zip->open('{$package}');\r\n");
  fwrite($f, "\$zip->extractTo('./');\r\n");
  fwrite($f, "\$zip->close();\r\n");
  fwrite($f, "?" . ">");
  fclose($f);
}

Set font size in Win32 API EDIT Window

i have recently been attempting to write a small text editor application, and the main problem i found was migrating notepad settings over to my application, the font for 10pt was stored as 100.

obviously, i needed to divide by 10, but when i did this, the font came out so small it was unreadable.

after some digging, i found the following works perfectly.

int m_height = -MulDiv(g_point_size/10, GetDeviceCaps(m_dc, LOGPIXELSY), 72);

once you have done this, just SendMessage to the EDIT you want to set the font size of, and bingo, we have a correct font size

Javascript Sudoku Solver using jQuery

I took the time earlier in the week to write a html/javascript sudoku solver. This code could be either used to cheat at sudoku or used as a basis for creating an online sudoku game.

Either way, have fun: http://www.bizzeh.com/solver/

Init Google Gears with jQuery

I took a look around the web for a jQuery plugin for google gears as i would like to initialise gears on user input, and not as the web page loads, but could not find one anywhere.

So i have written the following plugin, based on googles own gears_init.js code which inits gears on page load.

/*
 * jQuery Gears Init by Darren Horrocks
 *
 * jQuery Plugin to init google gears at any point during a page
 *
 * code based on gears_init.js from http://code.google.com/apis/gears/gears_init.js
 *
 */
(function() {
  jQuery.initGears = function() {
    // We are already defined. Hooray!
    if (window.google && google.gears) {
      return;
    }

    var factory = null;

    // Firefox
    if (typeof GearsFactory != 'undefined') {
      factory = new GearsFactory();
    } else {
      // IE
      try {
        factory = new ActiveXObject('Gears.Factory');
        // privateSetGlobalObject is only required and supported on IE Mobile on
        // WinCE.
        if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
          factory.privateSetGlobalObject(this);
        }
      } catch (e) {
        // Safari
        if ((typeof navigator.mimeTypes != 'undefined') && navigator.mimeTypes["application/x-googlegears"]) {
          factory = document.createElement("object");
          factory.style.display = "none";
          factory.width = 0;
          factory.height = 0;
          factory.type = "application/x-googlegears";
          document.documentElement.appendChild(factory);
        }
      }
    }

    // *Do not* define any objects if Gears is not installed. This mimics the
    // behavior of Gears defining the objects in the future.
    if (!factory) {
      return;
    }

    // Now set up the objects, being careful not to overwrite anything.
    if (!window.google) {
      google = {};
    }

    if (!google.gears) {
      google.gears = {factory: factory};
    }
  };
})();

You can now initialise gears using the the jQuery class or the dollar shortcut.

jQuery.initGears();
$.initGears();

Move Minimize, Maximize and Close window buttons back to the right on Ubuntu

As you know, the close, maximize and minimize buttons belong on the right hand side of the window title bar. For some reason in recent history, ubuntu decided to move them to the left hand side to be more inline with Mac OSX windows. Considering ubuntu is supposed to be an operating system aimed at luring people away from windows, this is a bad choice.

There is however a very simple way of moving these buttons back to the right hand side where they belong.

You first need to open up a terminal window “Applications > Accessories > Terminal” and type the following command:

sudo gconf-editor

This will load the gnome configuration editor. You will then need to navigate to “apps > metacity > general” in gconf-editor and find the “button_layout” setting.

Once you have found this, you need to change it from what it currently reads to:

close,minimize,maximize:

Once you have done this, you will see that the window buttons go back to where they belong and all is well with the world again.

PHP Keyword Generator and Keyword Density Generator

What we do here is first, create an array of bad words that we want to filter out, ie, the most common words in the most common languages such as “and” “or” “are”.

We also need to have a lower boundary to check against, most search engines have a lower word bound of 3 characters, so this is what we will use here.

We now check valid keywords against a string of text which will explode the string into an array based on commas or spaces and check each word against our list and that its 3 characters or greater. If we are not in the bad words list and we are 3 characters or greater, add it to the valid array, and if we are already there, increase the count by 1.

once we have cycled through all the words, we then order by largest first to smallest and then return our array.

we now have an array of words ordered by their popularity in the string that was given.

function get_filter_words() {
  $words = array('000', ..., 'zwölf' );
  return $words;
}

function is_valid_keyword($word) {
  $common_words = get_filter_words();

  return (strlen($word) >= 3 && !in_array($word, $common_words)) ? true : false;
}

function get_valid_keywords($words) {
  $word_arr = array();
  $word_ret = array();

  if(!is_array($words)) {
    $word_arr = preg_split("/[\s,]/", $words, -1, PREG_SPLIT_NO_EMPTY);
  }

  foreach($word_arr as $word) {
    if(is_valid_keyword($word)) {
      if(empty($word_ret[$word])) {
        $word_ret[$word] = 1;
      } else {
        $word_ret[$word]++;
      }
    }
  }

  arsort($word_ret, SORT_NUMERIC);

  return $word_ret;
}

Btw, you need to find your own bad word list

PHP Data Optimisation / PHP Function Optimisation

Using the keyword generator code from the previous post, i have written a small example to benchmarking script to test it setting up the array in get_filter_words with 2200 keywords:

The test code is as follows:

$text = strip_tags(file_get_contents('http://www.bizzeh.com/'));

for($x=0; $x<3; $x++) {
  $start = microtime(true);
  for($y=0;$y<100; $y++) {
    $ar = get_valid_keywords($text);
  }
  $end = microtime(true);

  echo($end-$start . "<br/>");
}

Using the default get_filter_words function we get average execution times of:

33.2730691433

I decided to optimise this function slightly to improve performance:

function get_filter_words() {
  static $words;
  if(empty($words)) $words = array('000', ..., 'zwölf' );
  return $words;
}

Defining $words as static allows it to persist across the entire script without being cleared on return, and since we are now checking if its empty and only loading the array if it is empty, we are now saving quite a lot of script time:

9.74925804138

Reset The Internet

The following is an example of the sort of work it would take to back up the data on the internet. Destroy the current implementation, and create a new one.

Where to start?

Assuming that all parties involved in something as large scale as resetting the entire internet have agreed to actually doing this, and doing so at no extra cost to the customer (me and you) we would first need to consider how, and where, all the data that is currently on the internet will be backed up.

The shear scale of the internet as it currently stands is unimaginable, the number of domain names registered globally now totals more than 138 million, according to the second quarter 2007 Domain Name Industry Brief published by VeriSign, a provider of digital infrastructure for the networked world.

The largest top-level domains (TLD) in terms of total base of registrations are .com, .de (Germany), .net, .uk (United Kingdom), .cn (China) and .org.

Backing up the domain name database

Let us work out how much space a raw database would take up to simply store the records of the domain name, two domain name servers, and for arguments sake, a 32bit signed integer to represent the unix timestamp of when the domain was registered, and for now, we will forgo all the other information we know domain names carry. Say we stick to the maximum 63 characters originally set out for domain names and use 8 bit characters.

63characters x 8bits per character = 504 bytes

Now we add on the 32 bits for the date first registered.

504 + 32 = 536

We now need to make sure we have enough room to store two domain name servers from 0.0.0.0 to 255.255.255.255, so we need a field that can hold 15 characters, or, we can use another 32 bit integer for each of the domain name servers and store it in its address format.

536 + (32 x 2) = 600

So now we have 600 bits per row to store this information. Now we need to find out what that would be in real terms of storing 138 million domain names.

600 x 138,000,000 = 82,800,000,000bits

82,800,000,000 / 8 = 10,350,000,000bytes

10350000000 / 1024 / 1024 = 9870.5mb

So we have over 9000mb of information just stored in those fields, the central database would also have to store the owner, the address of the owner, the technical contact, and the administrative contact. The ISP that was used to register the domain name would also have to be stored along with the last renewal date and various others. With this extra data we could increase this figure by quite an amount.

Backing up the web

To give some context to the size of just the World Wide Web (only one of the services that currently runs on the internet), the BBC currently has 5.43 million pages indexed in Google, ranging from their homepage at 120kb to a media rich news page of around 250kb so if we take an average of half way between (185kb) to work this out, everyone can be happy:

185kb x 5,340,000 = 987,900,000kb = 964,746mb = 942gb

Say we were to back up all that data on to a set of DVD’s, an standard DVD claims 4.7gb storage on the front of the disk, where it is actually closer to 4.4gb. To make this easier we assume that the BBC have not compressed any of their data, but have packaged it into a set of 4.4gb files (multi-part rar files or multi part tar files) so that we do not run into the problem caused by having a lot of small files.

942gb / 4.4gb = 214.1 DVD’s

So we would need 215 DVD’s to simply back up bbc.co.uk (since we cant have 0.1 of a DVD), and this assumes that we are simply storing the data hoping that nothing goes wrong with any of the discs, so a recovery record of 5% in WinRAR could be added which would be sufficient enough to recover all text based data within the files, this would push the 942gb to 989gb.

989gb / 4.4gb = 224.7 DVD’s

Now we need 225 DVD’s in order to back up the BBC and ensure that we have some sort of recovery record in case of data corruption because of a bad copy or a scratched disc.

To be continued…

Recreate target=_blank with javascript

Licence: BSD

This is a piece of code that i wrote for replacing the target=”_blank” for xhtml, as the target blank method of creating popup URLS for anchors within websites has been removed in xhtml 1.0. This code finds all links within a web page that have a href tag (an actual link) and that contain a rel=”external” tag (telling the element that the relationship to the current site is external), once it has done this it creates a dynamic function for the anchor and attaches it to the anchor. When a user clicks on the anchor, the script now attempts to create a new window and navigate to the url via the new window. If it is unable to create a new window, an alert will let the user know that a popup blocker has prevented the window from opening (unlike the rest of the scripts like this, which simply try and open the window and do nothing if it fails).

step 1. create a file named xhtmltb.js and paste the following code in to it.

function externalLinks() {
  //we need getElementsByTagName for this to work
  if (!document.getElementsByTagName) return;

  //get all the anchors within the document
  var anchors = document.getElementsByTagName("a");
  for (var i=0; i<anchors.length; i++) { //loop through all the anchors
    var anchor = anchors[i]; 

    //check to make sure that we have a href, so its a real hyperlink
    //and make sure that we have a ref and its set to external
    if (anchor.getAttribute("href") && anchor.getAttribute("rel") == "external") {

      //assign the dynamic function to the onclick event.
      anchor.onclick = function(x) {
        //store the variable so that we can actually use it within each function
        var p = x;
        return function() {
          var w = window.open(p); //try and open up a new window with the url
          if(!w) { //check to see if the window opened
            //let the user know that a window didnt open
            alert("A popup blocker seems to have blocked the window from opening");
          }

          //return false to make sure the browser doesnt navigate away in the current window also
          return false;
        }
      }(anchor.getAttribute("href")); //pass through the href for this anchor
    }
  }
} 

//make sure we only set everything up on load
//after the DOM has been inited
window.onload = externalLinks;

step 2. place it in the same directory as your html files.

step 3. add the following code into the head part of your html file.

<script type="text/javascript" src="xhtmltb.js"></script>

step 4. add rel=”external” to the anchor link, e.g.

<a href="http://www.bizzeh.com" rel="external">bizzeh's portfolio</a>

now you will notice that when you click on the links that have rel external, open up in a new window. though, this version will detect a window that did not open, due to a popup blocker and warn the user that the window did not open.

Multi-CPU-Aware Multithreading Code for C++

This is an example piece of code that shows how to count the number of processors/cores there are in a system, create a thread for each and assign each thread to a specific processor.
Useful if you want to write applications that do a lot of heavy processing and you wish to make use of dual/tri/quad core processors to make everything that bit better.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>

HANDLE *m_threads = NULL;
DWORD_PTR WINAPI threadMain(void* p);

DWORD_PTR GetNumCPUs() {
  SYSTEM_INFO m_si = {0, };
  GetSystemInfo(&m_si);
  return (DWORD_PTR)m_si.dwNumberOfProcessors;
}

int wmain(int argc, wchar_t **args) {
  DWORD_PTR c = GetNumCPUs();

  m_threads = new HANDLE[c];

  for(DWORD_PTR i = 0; i < c; i++) {
    DWORD_PTR m_id = 0;
    DWORD_PTR m_mask = 1 << i;

    m_threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadMain, (LPVOID)i, NULL, &m_id);
    SetThreadAffinityMask(m_threads[i], m_mask);

    wprintf(L"Creating Thread %d (0x%08x) Assigning to CPU 0x%08x\r\n", i, (LONG_PTR)m_threads[i], m_mask);
  }

  return 0;
}

DWORD_PTR WINAPI threadMain(void* p) {
  return 0;
}

<< Latest posts