Easy Pop-Ups with JQuery

JQuery is a powerful Javascript framework and I recently wanted to use it to make a popup submenu for MausJewelers.com on non-touch devices. I also wanted to position the popup dynamically on pageload since I wasn’t sure where the link that would trigger the popup would be positioned since the site is responsive.
 
You start with a DIV that contains the content to be displayed that you can trigger using the OnMouseOver event on a link or other HTML element. You can hide the popup using the OnMouseOut event event. In this example, the popup is triggered when the user positions their mouse over the Showcase link as shown here:
Showcase Popup
 
The trickiest part comes when you want to trigger the popup but you want to allow the user to move their mouse over the popup without causing the popup to disappear since their mouse is leaving the link.
 
To achieve this, you need to set up a timeout mechanism that will allow you hide the popup only when the user is NOT hovering the link or the popup. After that it is a matter of positioning the popup so it is under the link (and the user can move between the link and the popup. Here is a bit of code that I used for Maus Jewelers.
<!-- The Nav menu, I am using Bootstrap so this will be hidden on extra small devices -->
<div class="header-bottom header-nav hidden-xs">
    <ul class="nav navbar-nav">
          <li class="<?php checkActive("Location", $section); ?>"><a href="/location">Location</a></li>
          <li class="<?php checkActive("Services", $section); ?>"><a href="/services">Services</a></li>
          <li class="<?php checkActive("About", $section); ?>"><a href="/about">About Us</a></li>
          <li class="<?php checkActive("Showcase", $section); ?>" onmouseover="openPopup();" onmouseout="closePopup(true);" id="link"><a href="/showcase">Our Showcase</a></li>
         <li class="<?php checkActive("Home", $section); ?>"><a href="/">Home</a></li>
   </ul>
</div>

<!-- The popup -->
<div id="popup" style="display:none; z-index:10; position:absolute; top: 135px;" onmouseover="openPopup();" onmouseout="closePopup(true);" class="popup hidden-xs">
     <!-- I manually position the div so it will be far enough down the on the page. In this case, the nav link will not change it's top position. I am also using Bootstrap so this will be hidden on extra small devices. -->
     Hello Popup.
</div>

<script type="text/javascript">
var enablePopup = true; // if set to false, we won't open a popup
var pixelOffsetFromLink = 75; // The number of pixels to move to the left, from the link, this helps to align the popup

// Global variables
var popupOpen = false; // Indicates if the popup is currently open
var popupTimer = null; // Is a timer that triggers the closePopup function

/**
 * Calculate where the popup should be positioned based on where the link is currently at
 * 
 * @return null
 */
function calculatePopupPosition() {
     var $popup = $("#popup");
     var $link = $("#link");
     $popup.css("left", ($link.offset().left - pixelOffsetFromLink) + "px");
     
     return null;
}

/**
 * Close the popup if the popup is open and we don't want to set a timer
 * 
 * @param boolean setTimer: Indicates if we should set the timer and then close the popup after the timer's function is triggered
 *
 * @return null
 */
function closePopup(setTimer) {
     // Return if the popup isn't open
     if (!popupOpen) {
          return null;
     }
     
     // If we have a popup timer already, clear it so we can make a new one
     if (popupTimer != null) {
          window.clearTimeout(popupTimer);
          popupTimer = null;
     }
     
     // If we have set the timer, we will return early but set a timer to trigger this function and actually close the popup
     if (setTimer) {
          popupTimer = window.setTimeout("closePopup(false);", 250);
          return null;
     }    
    
     // Check if the mouse is over the popup, if it is, keep the popup open

     // If we aren't hovering anymore, close the popup and remove the hover class from the link
     if ($("#link:hover").length == 0 && $("#popup:hover").length == 0) {
          $("#popup").hide();
          popupOpen = false;
          $("#link:nth-child(1)").removeClass("hover");
     }

     return null;
}

/**
 * Open the popup
 *
 * @return null
 */
function openPopup() {
     // If the popup is open or if we don't want to show a popup at all, return
     if (popupOpen || !enablePopup) {
          return null;
     }
    
     popupOpen = true;
     calculatePopupPosition();
     $("#popup").show();
    
     // Give the link a hover class
     $("#link:nth-child(1)").addClass("hover");

     return null;
}
</script>

Caching the results of a PDO Query in Memcache

This is a quick example of code that will prepare a PDO statement and cache the results in Memcache.

It is easiest to use the two following sets of instructions to set up a LAMP environment that will handle the PHP, PDO, and Memcache packages that the code uses:

  1. How To Install Linux, Apache, MySQL, PHP (LAMP) stack on Ubuntu
  2. How To Install and Use Memcache on Ubuntu 12.04

Code

<?php
function db_connect() {
	global $memcache, $db;

	// Connect to the Memcache server
	$memcache = new Memcache();
	$memcache->pconnect('localhost', 11211);

	// Connect to the Database using PDO
	$host = "localhost";
	$dbname = "test";
	$user = "test";
	$pass = "test";

	try {
		$db = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
	} catch (PDOException $e) {
		die($e->getMessage());		
	}
}

function db_fetch_all($sql, $params = array(), $use_cache = true) {
	global $memcache, $db, $cache_expiration;

	$result = false;
	if ($use_cache) {
		// Generate a key for the cache
		$cache_key = md5($sql . serialize($params));
		$result = $memcache->get($cache_key);
	}

	if (!$result) {
		// Cache Miss: Prepare the sql and recache it
		$sth = $db->prepare($sql);
		
		// This handles ? within a sql query
		// i.e. "SELECT id FROM example WHERE name = ?";
		$i = 0;
		foreach ($params as $param) {
		    $sth->bindParam(++$i, $param);
		}

		// This handles :params within queries
		// "SELECT id FROM example WHERE name = :name";
		foreach ($params as $key => $value) {
		    // keys must be in the form :key within the query
		    $sth->bindParam($key, $value);
		}

		$sth->execute();
		$result = $sth->fetch(); // Fetch the entire result into an array
		
		// Cache expires in 10 seconds
                $cache_key = md5($sql . serialize($params));
		$cache_expiration = 10;
		$memcache->set($cache_key, serialize($result), MEMCACHE_COMPRESSED, $cache_expiration);

		echo "used mysql";
	} else {
		// Cache Hit
		echo "used memcache";
	}

	return $result;
}

echo "Time: " . time() . "<br />";
if (class_exists("Memcache")) {
	db_connect();

	// The query only works with ? as variables in the prepared statement
	$query = "SELECT id FROM example WHERE name = ?";
	$result = db_fetch_all($query, array("new_data"));
} else {
	echo "Memcache not installed :(";
}
?>

Rijndael / AES (128 bit) in VB.net, PHP, Python

Being able to transport encrypted data is important in some of my projects at work. One-way hashes using MD5 usually suffice for most encryption purposes but Symmetric Encryption algorithms are important for encrypting and then decrypting data. For this, we use the Rijndael and AES algorithm in a few different languages. Here is what we do for VB.net, PHP, and Python. I also take no responsibility for misuse of this code.

Note: You will see a string replace which is necessary for passing encrypted data through a URL.

VB.net:

' Keys required for Symmetric encryption / decryption
Dim rijnKey As Byte() = {&H1, &H2, &H3, &H4, &H5, &H6, &H7, &H8, &H9, &H10, &H11, &H12, &H13, &H14, &H15, &H16}
Dim rijnIV As Byte() = {&H1, &H2, &H3, &H4, &H5, &H6, &H7, &H8, &H9, &H10, &H11, &H12, &H13, &H14, &H15, &H16}

Function Decrypt(S As String)
If S = "" Then
Return S
End If
' Turn the cipherText into a ByteArray from Base64
Dim cipherText As Byte()
Try
' Replace any + that will lead to the error
cipherText = Convert.FromBase64String(S.Replace("BIN00101011BIN", "+"))
Catch ex As Exception
' There is a problem with the string, perhaps it has bad base64 padding
Return S
End Try
'Creates the default implementation, which is RijndaelManaged.
Dim rijn As SymmetricAlgorithm = SymmetricAlgorithm.Create()
Try
' Create the streams used for decryption.
Using msDecrypt As New MemoryStream(cipherText)
Using csDecrypt As New CryptoStream(msDecrypt, rijn.CreateDecryptor(rijnKey, rijnIV), CryptoStreamMode.Read)
Using srDecrypt As New StreamReader(csDecrypt)
' Read the decrypted bytes from the decrypting stream and place them in a string.
S = srDecrypt.ReadToEnd()
End Using
End Using
End Using
Catch E As CryptographicException
Return S
End Try
Return S
End Function


Function Encrypt(S As String)
'Creates the default implementation, which is RijndaelManaged.
Dim rijn As SymmetricAlgorithm = SymmetricAlgorithm.Create()
Dim encrypted() As Byte
Using msEncrypt As New MemoryStream()
Dim csEncrypt As New CryptoStream(msEncrypt, rijn.CreateEncryptor(rijnKey, rijnIV), CryptoStreamMode.Write)
Using swEncrypt As New StreamWriter(csEncrypt)
'Write all data to the stream.
swEncrypt.Write(S)
End Using
encrypted = msEncrypt.toArray()
End Using

' You cannot convert the byte to a string or you will get strange characters so base64 encode the string
' Replace any + that will lead to the error
Return Convert.ToBase64String(encrypted).Replace("+", "BIN00101011BIN")
End Function

PHP:

$rijnKey = "\x1\x2\x3\x4\x5\x6\x7\x8\x9\x10\x11\x12\x13\x14\x15\x16";
$rijnIV = "\x1\x2\x3\x4\x5\x6\x7\x8\x9\x10\x11\x12\x13\x14\x15\x16";
function Decrypt($s){
global $rijnKey, $rijnIV;

if ($s == "") { return $s; }

// Turn the cipherText into a ByteArray from Base64
try {
$s = str_replace("BIN00101011BIN", "+", $s);
$s = base64_decode($s);
$s = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $rijnKey, $s, MCRYPT_MODE_CBC, $rijnIV);
} catch(Exception $e) {
// There is a problem with the string, perhaps it has bad base64 padding
// Do Nothing
}
return $s;
}

function Encrypt($s){
global $rijnKey, $rijnIV;

// Have to pad if it is too small
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, 'cbc');
$pad = $block - (strlen($s) % $block);
$s .= str_repeat(chr($pad), $pad);

$s = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $rijnKey, $s, MCRYPT_MODE_CBC, $rijnIV);
$s = base64_encode($s);
$s = str_replace("+", "BIN00101011BIN", $s);
return $s;
}

Python 2.7:
You must first install the pyCrypto package which gives you access to AES functions. If you are using Windows, you can go to http://www.voidspace.org.uk/python/modules.shtml#index to download the pyCrypto binary.


from Crypto.Cipher import AES
import base64
import os

key = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16"
iv = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16"
text = "10"
replace_plus = "BIN00101011BIN"

# the block size for the cipher object; must be 16, 24, or 32 for AES
BLOCK_SIZE = 16

def repeat_to_length(string_to_expand, length):
return (string_to_expand * ((length/len(string_to_expand))+1))[:length]

pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) \
* chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s : s[0:-ord(s[-1])]

# one-liners to encrypt/encode and decrypt/decode a string
# encrypt with AES, encode with base64
def EncodeAES(s):
c = AES.new(key, AES.MODE_CBC, iv)
s = pad(s)
s = c.encrypt(s)
s = base64.b64encode(s)
return s.replace("+", replace_plus)

def DecodeAES(enc):
c = AES.new(key, AES.MODE_CBC, iv)
enc = enc.replace(replace_plus, "+")
enc = base64.b64decode(enc)
enc = c.decrypt(enc)
return unpad(enc)

# encode a string
encoded = EncodeAES(text)
print 'Encrypted string:', encoded

# decode the encoded string
decoded = DecodeAES(encoded)
print 'Decrypted string:', decoded