jQuery Integer Only Text Inputs using qTip for notification

I needed a great, unobtrusive way to notify a web site visitor that they can only enter whole numbers into fields on a web form. This is the JavaScript I came up with using jQuery and qTip  This is easily modified to support numeric characters of any sort – decimal points, commas, whatever you want.  It does not enforce any particular rules – it is primarily a keystroke filter.

I allow numbers and navigation keys, but disallow everything else. The code is documented inline.

Please don’t forget that if you use this to not rely on it for anything except relieving user frustration. You should always do server side validation as well

And this is the way it looks in my project:

.

One thing I should note: I’m using this together with Knockout.js  without any weird side effects – they are working nicely together.

$(function()
{
    $('input.intOnly' ).live( 'paste',
    function(event)
    {
        // we could loop across the value and validate it, but I'm too lazy
        event.preventDefault();
    });

    $("input.intOnly").live( 'blur',
    function( event )
    {
        $(this).qtip('destroy');
    });

    $("input.intOnly").live( 'keydown',
    function( event )
    {
        if (
            event.keyCode == 46  || // delete
            event.keyCode == 8   || // backspace
            event.keyCode == 9   || // tab
            event.keyCode == 224 || // command key on mac
            event.keyCode == 18  || // alt key
            event.keyCode == 16  || // shift key
            event.keyCode == 17  || // control key
            ( event.keyCode >= 48 && event.keyCode <= 57  ) || // numbers
            ( event.keyCode >= 96 && event.keyCode <= 105 ) || // numeric keypad
            ( event.keyCode >= 37 && event.keyCode <= 40  )    // arrow keys
        )
        {
            return;
        }
        event.stopImmediatePropagation();
        event.preventDefault();
        $(this).qtip(
        {
            content: 'Only whole numbers are allowed.',
            show: { ready: true },
            hide: { fixed: true, delay: 100000 }
        });
    });
});
Advertisements

PHP based COMET Using iframes

So I’m doing some research into, and will probably be using COMET for a project I’m working on. Yes, I know that the Apache-PHP combination is not the best for COMET, however this will be on an administrative dashboard with one or two simultaneous users at most.  I’m no COMET expert – this is my first foray into the technology.  If I learn amazing things while doing a live implementation I’ll write more articles.

While searching I ran across several tutorials and some code, but nothing that was a simple 2 file “Here’s how it’s done” example.

The basic premise (this is not new stuff – I ran across stuff from the mid 2000’s while searching) is that you have an iframe that loads a long-running PHP script that is generating <script> tags.  The JavaScript in these tags must reference the parent document.  In my test code I’m referencing a function defined in the parent document.

Some takeaways:

  1. If the script that’s referenced by your iframe doesn’t output enough data before it starts outputting <script> tags, you’ll see a delay until some sort of buffer is filled up.  I’m blaming Firefox, but I’m not certain as I didn’t investigate further.  You’ll notice a bunch of white space in my sample code – that’s a whole ton of spaces to stop the delay I was seeing in Firefox.
  2. On localhost this is very fast.  I had to introduce a usleep into the code so that it wouldn’t be so fast as to be unusable.  I haven’t tested against a remote web server, but I can assure you this will be dramatically faster than ajax polling.
  3. Firefox’s javascript engine seems to process the <script> tags being returned in the iframe faster than the DOM is able to update. I view this as good news.
  4. You must output the opening and closing script tags each time you want to update the browser.  Leaving them out will cause the browser to wait until the request is loaded – the opposite of what we’re trying to accomplish.

The example code is not an infinite loop – it’s a long running script (just a very long for loop).  In practice I’ll be using other factors to determine when to break out of an output loop.  The project requirements call for this to be running for hours so we’ll find out if that tests the limits of what this approach can handle.

Download the code

Double Reference Variable Assignments in PHP

I just got through tracking down a very pernicious bug.

The problem was that an array assigned to an object was retaining its original link after cloning.  The original array was created with its values being assigned by reference.  This wouldn’t have been a problem in and of itself, but additionally there was a second array being created with a reference to the same variable.  This was both unnecessary and certain death to my script.

The takeaway from this is to avoid unnecessary variable assignment by reference. The original code was written over two years ago.

If I recall correctly my justification for using references was to save memory.

This is wrong.

Don’t think about references in a context of memory consumption (especially since PHP allocates on write), think about references in a context of “How do I need to treat this data?”

Here is the full script that is broken. Notice in the foreach two referential assignments.

$in = array( 'a' => '123', 'b' => '456' );
$vars = array();

foreach( $in as $key => $val )
{
	$_GET[$key] =& $val;
	$vars[] =& $val;
	unset( $val );
}

class test
{
	protected $_data;

	public function set( $data )
	{
		$this->_data = $data;
	}

	public function setVar( $key, $val )
	{
		$this->_data[$key] = $val;
	}
}

header( 'content-type: text/plain' );

echo 'Should be 123 and 456' . PHP_EOL;
var_dump( $_GET );

$test = new test();
$test->set( $_GET );

echo 'Should be 123 and 456' . PHP_EOL;
var_dump( $_GET );

$second = clone $test;
$second->setVar( 'a', 'abc' );

echo 'Should be 123 and 456' . PHP_EOL;
var_dump( $_GET );

Output

Should be 123 and 456
array(2) {
  ["a"]=>
  &string(3) "123"
  ["b"]=>
  &string(3) "456"
}
Should be 123 and 456
array(2) {
  ["a"]=>
  &string(3) "123"
  ["b"]=>
  &string(3) "456"
}
Should be 123 and 456
array(2) {
  ["a"]=>
  &string(3) "abc"
  ["b"]=>
  &string(3) "456"
}

Corrected Script

$in = array( 'a' => '123', 'b' => '456' );

foreach( $in as $key => $val )
{
	$_GET[$key] = $val;
}

class test
{
	protected $_data;

	public function set( $data )
	{
		$this->_data = $data;
	}

	public function setVar( $key, $val )
	{
		$this->_data[$key] = $val;
	}
}

header( 'content-type: text/plain' );

echo 'Should be 123 and 456' . PHP_EOL;
var_dump( $_GET );

$test = new test();
$test->set( $_GET );

echo 'Should be 123 and 456' . PHP_EOL;
var_dump( $_GET );

$second = clone $test;
$second->setVar( 'a', 'abc' );

echo 'Should be 123 and 456' . PHP_EOL;
var_dump( $_GET );

Correct Output

Should be 123 and 456
array(2) {
  ["a"]=>
  string(3) "123"
  ["b"]=>
  string(3) "456"
}
Should be 123 and 456
array(2) {
  ["a"]=>
  string(3) "123"
  ["b"]=>
  string(3) "456"
}
Should be 123 and 456
array(2) {
  ["a"]=>
  string(3) "123"
  ["b"]=>
  string(3) "456"
}

Mixing MySQL InnoDB and MyISAM tables with transactions

Just learned this from personal experience.  Hoping to save someone else some pain.

I tried the following searches:

mysql transaction partial rollback
does fetching commit an innodb transaction
innodb rollback not working

The symptoms I was experiencing included inserted records were rolled back, but an update to a table was not. My PHP code threw an exception inside a transaction, and the catch did a rollback, but the update still went through.

The problem was that the table I was updating happened to be MyISAM. MySQL silently ignored the fact that I included a table in my transaction that couldn’t be rolled back. When the rollback occurred, this was also silently ignored.

Moral of the story: use all InnoDB if you’re going to be doing transactions.

Making Sense of Variable Scope in PHP 5 OOP

I’ve learned a lot about PHP5 OOP visibility recently.  I’m posting a test script that will share some of my discoveries.

Take away:

  1. Private really does mean private.
  2. Visibility keywords are honored while cloning
  3. PHP does not enforce the visibility keywords on variables using a fatal error.
    It uses an E_NOTICE : Notice: Undefined property
define( 'SCRIPT_EOL', '<br>' );

abstract class a_base_class
{
    private $name = 'Johannes Kepler';
    protected $color = 'Green';

    public function __set($name, $value)
    {
        throw new Exception( 'a_base_class - Undefined or private property: ' . $name );
    }

    public function __clone()
    {
        // this does work - $this->name is private but is accessible in this class
        $this->name = 'Isaac Newton';
    }

    public function getName()
    {
        return $this->name;
    }

    public function echoName()
    {
        echo $this->name;
    }
}

class exampleClass1 extends a_base_class
{
    function __clone()
    {
        // this does not work - $this->name is private to ac and can't be modified here
        $this->name = 'Isaac Newton';
    }

    function echoName()
    {
        // this will issue an E_NOTICE because the variable is undefined in this class (private variables do not carry through to descendants)
        echo $this->name;
    }

    function echoColor()
    {
        echo $this->color;
    }
}

class exampleClass2 extends a_base_class
{
    public function __clone()
    {
        $this->color = 'Red';
        // without this, $this->name will not get changed to Isaac Newton
        parent::__clone();
    }

    public function echoColor()
    {
        echo $this->color;
    }
}

echo '</pre>

<hr />

<pre>
';
echo '</pre>
<h2>exampleClass1</h2>
<pre>
';
$instance = new exampleClass1();
echo 'calling echoName()' . SCRIPT_EOL;
$instance->echoName();
echo 'echo $instance->name' . SCRIPT_EOL;
echo $instance->name . SCRIPT_EOL;
echo SCRIPT_EOL;
echo 'echoing getName()' . SCRIPT_EOL;
echo $instance->getName(); // calling public method on base class
echo SCRIPT_EOL;
echo 'calling echoColor()' . SCRIPT_EOL;
$instance->echoColor();
echo SCRIPT_EOL;

try
{
    $newInstance = clone $instance;
}
catch( Exception $e )
{
    echo SCRIPT_EOL . '------------------------------------------------' . SCRIPT_EOL;
    echo "Exception Thrown: " . $e->getMessage();
    echo SCRIPT_EOL;
echo '
';
    echo $e->getTraceAsString();
    echo '

';
    echo SCRIPT_EOL . '------------------------------------------------' . SCRIPT_EOL;
}
echo SCRIPT_EOL;
echo 'var_dump' . SCRIPT_EOL;
var_dump( $newInstance );

echo '</pre>

<hr />

<pre>
';
echo '</pre>
<h2>exampleClass2</h2>
<pre>
';

$instance = new exampleClass2();
echo 'calling echoName()' . SCRIPT_EOL;
$instance->echoName();
echo SCRIPT_EOL;
echo 'echo $instance->name' . SCRIPT_EOL;
echo $instance->name . SCRIPT_EOL;
echo 'echoing getName()' . SCRIPT_EOL;
echo $instance->getName(); // calling public method on base class
echo SCRIPT_EOL;
echo 'calling echoColor()' . SCRIPT_EOL;
$instance->echoColor();
echo SCRIPT_EOL;

try
{
    $newInstance = clone $instance;
}
catch( Exception $e )
{
    echo SCRIPT_EOL . '------------------------------------------------' . SCRIPT_EOL;
    echo "Exception Thrown: " . $e->getMessage();
    echo SCRIPT_EOL;
    echo $e->getTraceAsString();
    echo SCRIPT_EOL . '------------------------------------------------' . SCRIPT_EOL;
}

echo '
';
var_dump( $newInstance );
echo '

';

Output


exampleClass1

calling echoName()

Notice: Undefined property: exampleClass1::$name in /Users/timgallagher/Desktop/xampp/se/php5oop.php on line 43
echo $instance->name

Notice: Undefined property: exampleClass1::$name in /Users/timgallagher/Desktop/xampp/se/php5oop.php on line 73

echoing getName()
Johannes Kepler
calling echoColor()
Green

————————————————
Exception Thrown: a_base_class – Undefined or private property: name

#0 /Users/timgallagher/Desktop/xampp/se/php5oop.php(37): a_base_class->__set('name', 'Isaac Newton')
#1 /Users/timgallagher/Desktop/xampp/se/php5oop.php(84): exampleClass1->__clone()
#2 {main}

————————————————

var_dump

Notice: Undefined variable: newInstance in /Users/timgallagher/Desktop/xampp/se/php5oop.php on line 98
NULL


exampleClass2

calling echoName()
Johannes Kepler
echo $instance->name

Notice: Undefined property: exampleClass2::$name in /Users/timgallagher/Desktop/xampp/se/php5oop.php on line 108

echoing getName()
Johannes Kepler
calling echoColor()
Green

object(exampleClass2)#1 (2) {
  ["name:private"]=>
  string(12) "Isaac Newton"
  ["color:protected"]=>
  string(3) "Red"
}

Hiding values in URL’s using PHP

<?

header( 'content-type: text/plain' );
$h = '';
if ( array_key_exists( 'h', $_GET ) && ! empty( $_GET['h'] ) )
{
    $test = unserialize( gzuncompress( base64_decode( urldecode( urldecode( $_GET['h'] ) ) ) ) );
    if ( is_array( $test ) )
    {
        $h = $_GET['h'];
        $_GET = $test;
    }
}
elseif( count( $_GET) )
{
    $h = urlencode( urlencode( base64_encode( gzcompress( serialize( $_GET ), 9 ) ) ) );
}

list( $url ) = explode( '?', $_SERVER['REQUEST_URI'] );

if ( ! empty( $h ) )
{
    $url .= '?h=' . $h;
}

echo $url . "\n\n";

var_dump( $_GET );