Thursday, August 18
Tuesday, July 12
Warning: Not Enough Brain Space
Embarking on a new endeavor. Learning Spring MVC.
Friday, February 25
Export Query to CSV
It's been requested that I generate reports from the data stored in the database. They want to open them in Excel, so I decided to generate CSVs. Php5 added a nice function, fputcsv, that will format an array as a CSV and write it to the file.
$file = fopen('php://temp/maxmemory:'. (5*1024*1024), 'r+');
while($data = mysql_fetch_assoc($query)){
fputcsv($file, $data);
}
rewind($file);
$export = stream_get_contents($file);
fclose($file);
header('Content-type: application/csv');
header('Content-Disposition: atachment; filename="report.csv"');
echo $export;function unstrip_array($array){
foreach($array as &$val){
if(is_array($val)){
$val = unstrip_array($val);
}else{
$val = stripslashes($val);
}
}
return $array;
}fputcsv($file, unstrip_array($data));
Wednesday, February 2
Timestamp Field not Auto Update
I have a registration table with a timestamp field that I want to use the current timestamp when someone registers. If you just create a timestamp field in mysql, it acts as though you did:
`regdate` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMPThis is fine and dandy for some applications, but any time you update the record, it will update the timestamp. I did not want this. So, you can just create the table with:
`regdate` timestamp NOT NULL default CURRENT_TIMESTAMPBut, if like me, you have to alter the table, it' simple enough to do with:
ALTER TABLE registration CHANGE regdate regdate timestamp default CURRENT_TIMESTAMP;
Wednesday, January 19
Physical Address same as Mailing
This project has a need to know your physical location, but might need to mail you something too. Sometimes these are not the same, so we make input boxes for both. In most cases, they are the same, so we create a check box that says "Same as physical address." When they check it, the second set of address inputs are automatically filled and disabled.
So we start with a simple form.
<strong>Physical Address</strong>
<label for="pstr">Street *</label><input type="text" name="pstr" id="pstr" />
<label for="pstr2">Street 2</label><input type="text" name="pstr2" id="pstr2" />
<label for="pzip">Zip *</label><input type="text" name="pzip" id="pzip" />
<strong>Mailing Address</strong>
<label for="same">Same as Physical Address</label><input type="checkbox" name="same" id="same" value="same" />
<label for="mstr">Street *</label><input type="text" name="mstr" id="mstr" />
<label for="mstr2">Steet 2</label><input type="text" name="mstr2" id="mstr2" />
<label for="mzip">Zip *</label><input type="text" name="mzip" id="mzip" />
The jQuery has to not only populate and disable the fields when the box is checked, it has to make sure the validation passes. Then if someone changes their mind and unchecks the box, it has to un disable the boxes and clear them out.
$(document).ready(function(){
$('input:checkbox[name=same]').change(function(){
if($(this).is(':checked')){
$('#mstr').val($('#pstr').val());
$('#mstr2').val($('#pstr2').val());
$('#mzip').val($('#pzip').val());
$('#mstr').attr('disabled', 'disabled');
$('#mstr2').attr('disabled', 'disabled');
$('#mzip').attr('disabled', 'disabled');
$('#mstr').removeClass('error');
$('#mstr2').removeClass('error');
$('#mzip').removeClass('error');
}else{
$('#mstr').removeAttr('disabled');
$('#mstr2').removeAttr('disabled');
$('#mzip').removeAttr('disabled');
$('#mstr').removeAttr('value');
$('#mstr2').removeAttr('value');
$('#mzip').removeAttr('value');
}
});
});And with some formatting, it looks like this.
Thursday, December 23
Mailing with Joomla: HTML and Text
Joomla has its own built in version of PHPMailer called JMail. Hey, we set all these email configurations in the setup, might as well use those.
$mail =& JFactory::getMailer();Now we can define more stuff for useSMTP, but unless your server settings aren't standard, you don't really need to. But it's all in the config file too, easy way to see it all is just to print_r($config).
$config =& JFactory::getConfig(); //this is where we grab info from the config file
$mail->useSMTP(
$config->getValue('config.smtpauth'),
$config->getValue('config.smtphost'),
$config->getValue('config.smtpuser'),
$config->getValue('config.smtppass')
);
$HTMLmsg = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Message title</title>
</head>
<body>
<p>Here is some text. It looks nice.</p>
</body></html>';
$textmsg = "Here is some text. It looks ok.";
$mail->setBody(&HTMLmsg);
$mail->isHTML(true);
$mail->AltBody=&textmsg;
$mail->addRecipient('example@example.com');
$mail->setSender($config->getValue('config.mailfrom'));
$mail->setSubject('Test email');Well this seems good right? I spent a few minutes with this all set up, testing, but no email was sent. Oh yeah, forgot one very important line.$mail->send();
Friday, December 10
Ajax Username Check
<input type="text" name="uname" id="uname"><span id="checkuname">
$u = $_GET['u'];
require_once('db.php');
if($u <> ""){ //we don't want to display anything if the field is blank
$checkname = query("SELECT * FROM table WHERE username = '".$u."'");
if(num_rows($checkname) <> 0){
$desc = 'Already in use';
}else{
$desc = 'Ok to use!';
}
}
echo $desc;
$('#uname').keyup(function(){
$('checkuname').load('checkuser.php?u='+$(this).val(), function(response, status, xhr){
if(status == "error"){
var msg = "There was an error: ";
$('#checkuname').html(msg + xhr.status + " " + xhr.statusText);
}
});
});
Thursday, December 9
Style a button as a link
I have an invisible form that I want the user to submit with a link, keeping the illusion that it's not a form. I know you could submit the form with javascript (onclick="document.formName.submit();), but then if the user doesn't have javascript enabled, I'd still have to use a noscript tag and they'd see it as a form button. The solution is to style the button with CSS. something like:
.sublink {
color: #00f;
background-color: transparent;
text-decoration: underline;
border: none;
cursor: pointer;
}<input type="submit" class="sublink" value="Click this">
Tuesday, November 30
Valid Dates
OMG, two in one day!
if($row['indate'] == "Jan 01 1900 12:00AM") echo "";
else echo date("n/d/Y", strtotime($row['indate']));
if($_POST['indate'] <> ''){
$arr=split("/",$_POST['indate']);
$mm=$arr[0];
$dd=$arr[1];
$yy=$arr[2];
if(!checkdate($mm,$dd,$yy)){
$errormsg = 'Input is an invalid date: '.$_POST['indate'];
}
}References:
php.net
plus2net.com
Validate Integer Input
Php has an is_int() function, but it doesn't work with strings, unlike is_numeric() which will validate a numeric string. This was a big problem for me. The database required an int. My original solution was to force a numeric string to be an int with intval(), but the QA tester felt the integrity loss of data was too severe.
if(!filter_var($_POST['input'], FILTER_VALIDATE_INT)){
echo "validation failed, input must be an integer";
}
Thursday, November 18
Datepicker with Dynamic Fields
Previously, I added rows to an input table. I realised later, the datepicker fields I added didn't work on these dynamic fields. Looking at the form details with the firefox web developer toolbar, I noticed the original datepicker fields had an id assigned to them of dp+randomnumber, but the new ones didn't.
$('.datepicker').not('.hasDatePicker').datepicker();
Wednesday, November 17
255 varchar limit
Again, I have to use an MSSql database with php. I was having a problem: I'd insert a large amount of text into a varchar(1000) field, but when I tried to display it, only 255 characters came out. The problem has something to do with the drivers linux uses for php to connect to MSSql. There were two ways to handle this.
SELECT CAST(details as TEXT) from table
Thursday, July 29
Add Rows with Unique Name
A table of input boxes will be put into a database. The user may need to add more to the table.
<table id="infotable">JQuery:
<tr>
<th>Individual Name</th>
<th>Type</th>
<th>Number</th>
<th>Expires</th>
</tr>
<tr>
<td><input type='text' name='info[0][indname]' /></td>
<td><input type='text' name='info[0][type]' /></td>
<td><input type='text' name='info[0][num]' /></td>
<td><input type='text' name='info[0][exp]' /></td>
</tr>
<tr>
<td><input type='text' name='info[1][indname]' /></td>
<td><input type='text' name='info[1][type]' /></td>
<td><input type='text' name='info[1][num]' /></td>
<td><input type='text' name='info[1][exp]' /></td>
</tr>
</table>
$('#addinfo').click(function(){
var getcount = $('input[name^="info"]:last').attr('name');
var ncount = parseInt(getcount.substring(4,getcount.length-6))+1;
$("#infotable > tbody").append("<tr><td><input type='text' name='info["+ncount+"][indname]' size='28' /></td><td><input type='text' name='info["+ncount+"][type]' </td><td><input type='text' name='info["+ncount+"][num]' /></td><td><input type='text' name='info["+ncount+"][exp]' class='datepicker' /></td></tr>");
});The added tr has to be all on one like because javascript doesn't like like breaks. Wednesday, May 26
Easiest Datepicker Ever
There is a fast, easy way to add a date picker calendar to any form. jQuery! More specifically, jQueryUI.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/themes/base/jquery-ui.css" type="text/css" media="all" />
$('.datepicker').datepicker(); and any text field with the datepicker class will make a beautiful awesome calendar. Thursday, May 6
jQuery is Fun!
I'm having fun with jQuery and Fancybox. Not only can I do lightbox style effect with images and galleries, but I can use it for other things too.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>HTML:
<script type="text/javascript" src="/fancybox/jquery.fancybox-1.3.1.pack.js"></script>
<script type="text/javascript" src="/fancybox/jquery.easing-1.3.pack.js"></script>
<link rel="stylesheet" href="/fancybox/jquery.fancybox-1.3.1.css" type="text/css" media="screen" />
<script>
$(document).ready(function(){
$(".more").fancybox({
'titlePosition' : 'inside',
'transitionIn' : 'elastic',
'transitionOut' : 'elastic'
});
});
</script>
<a class="more" href="#popup1">HTML Popup</a>
<div style="display:none">
<div id="popup1" style="width:500px; height:220px; overflow:auto;">
<h2>Title</h2>
<p>Text text</p>
</div>
</div>
Tuesday, May 4
Creating an Org Chart with CSS
The trick is to use LOTS of divs. Every box and every line is its own div... and the whole thing is in another div.
Another thing they wanted was some of the boxes to expand to show more details. This was really easy to do with javascript and I used jQuery for the animations
So here's my divs:
<div id="container">You'll notice box 4 is expandable. Script below the css.
<div id="box1">
<h3 class="titles">Box 1</h3>
</div>
<div id="line1"></div>
<div id="box2">
<h2 class="titles">Box 2</h2>
</div>
<div id="line2"></div>
<div id="box3">
<h3 class="titles">Box 3</h3>
</div>
<div class="clear"></div>
<div id="line3"></div>
<div id="box4">
<h2 class="titles"><a class="show" href="#">Expandable</a></h2>
<div id="expand">
I am the contents of an expandable box
</div>
<p class="clear"></p>
</div>
<div id="box5">
<h2 class="titles">Box 5 has a longer sentence</h2>
</div>
<div id="line4"></div>
<div id="box6">
<strong>Box 6</strong>
</div>
<div id="line5"></div>
<div id="line6"></div>
<div class="clear"></div>
<div id="line7"></div>
<div id="line8"></div>
<div id="line9"></div>
<div class="clear"></div>
<div id="box7"><strong>Box 7</strong></div>
<div id="box8"><strong>Box 8</strong></div>
<div id="box9"><strong>Box 9</strong></div>
</div>
The css:
* { padding:0; margin:0; }
body { font-family: Arial,Helvetica,sans-serif; font-size: 80%; color: #000;}
h1{ font-size: 133%;}
h2 { font-size: 116%;}
h3{ font-size: 108%;}
h4 { font-size: 104%;}
#expand{ display:none; text-align:center; }
#container{
width:950px;
text-align:center;
margin:auto;
margin-top: 10px;
}
.clear { clear:both;}
.titles { text-align:center; padding:10px; }
#box1,#box2,#box3{
display:inline;
border: 1px solid #000;
float:left;
height:55px;
width:250px;
}
#line1,#line2{
font-size:0;
display:inline;
width: 96px;
height:1px;
float:left;
margin-top:23px;
background-color:#000;
}
#line3,#line5{
font-size:0;
width:1px;
height:35px;
background-color:#000;
margin:auto;
}
#box4 {
border: 1px solid #000;
width:200px;
height:55px;
margin:auto;
margin-bottom:10px;
text-align:left
}
#box5{
border:1px solid #000;
width:760px;
height:30px;
margin:auto;
}
#line4{
font-size:0;
height:20px;
width:1px;
background-color:#000;
margin:auto;
}
#box6{
border:1px solid #000;
width:300px;
height:75px;
margin:auto;
background-color:#FF0;
}
#line6{
font-size:0;
height:1px;
width:599px;
background-color:#000;
margin:auto;
}
#line7{
font-size:0;
height:20px;
width:1px;
background-color:#000;
margin-left: 175px;
display:inline;
float:left;
}
#line8,#line9{
font-size:0;
height:20px;
width:1px;
background-color:#000;
margin-left: 298px;
display:inline;
float:left
}
#box7{
border:1px solid #000;
width:200px;
height:40px;
margin-left:100px;
display:inline;
float:left;
padding-top:15px;
}
#box8{
border:1px solid #000;
width:150px;
height:40px;
margin-left:100px;
display:inline;
float:left;
padding-top:15px;
}
#box9{
border:1px solid #000;
width:150px;
height:40px;
margin-left:130px;
display:inline;
float:left;
padding-top:15px;
}And finally the JS:<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>jQuery was great for this because of their toggle function so I could use the same link to expand and contract the box.
<script>
$(document).ready(function(){
// expandable
$("a.show").toggle(function(){
$("#box4").animate({width: '940px', height: '225px'});
$("#expand").slideDown('medium');
},function(){
$("#box4").animate({width: '200px', height: '55px'});
$("#expand").slideUp('medium');
});
});
</script>
Tuesday, March 16
Accept Disclaimer and Redirect or Sessions in Joomla
Customer wants users to accept a disclaimer one time each visit to the site, then be redirected to the page. So if the user accepts the disclaimer, a session variable will be written and they will be redirected. This is a Joomla site, so the framework is already built for sessions and I wouldn't want to use regular php sessions.
//load joomla files
require_once ( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.'framework.php' );
$mainframe =& JFactory::getApplication('site');
$mainframe->initialise();
// get the session
$session =& JFactory::getSession();
$defaultvalue = 'reject';
$discl = $session->get('discl', $defaultvalue, 'disclaimer'); //get discl session value or 'reject' if not set
if($discl <> 'accept'){
$link = JRoute::_('index.php?option=com_content&view=article&id=43&Itemid=52');
$mainframe->redirect($link);//route them back to disclaimer page
}
// load joomla files
require_once ( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.'framework.php' );
$mainframe =& JFactory::getApplication('site');
$mainframe->initialise();
// get the session
$session =& JFactory::getSession();
$session->set('discl', 'accept', 'disclaimer');//set accept
$link = JRoute::_('index.php?option=com_content&view=article&id=1&Itemid=49');
$mainframe->redirect($link);//route them to page
Thursday, February 11
Updating Submit Disable to Include isNaN
The datanumber should be numeric, so I wanted to check on the frontend, before they even submit it. It was easy to add an else to the previous javascript function SearchVal().
function searchVal(){
if(document.getElementById('fname').value == 0
&& document.getElementById('lname').value == 0
&& document.getElementById('datanum').value == 0){
msg = 'At least one search field must be filled';
}else if(isNaN(document.getElementById('datanum').value)){
msg = 'Data number must be numeric';
}else{
dis = false;
msg = '';
}
if(dis == true){
document.getElementById('sub').disabled = true;
}else{
document.getElementById('sub').disabled = false;
}
document.getElementById('validmsg').innerHTML = msg;
}
Tuesday, February 9
Get Age From Birthday
function GetAge($Birthdate){
// Explode the date into meaningful variables
list($BirthYear,$BirthMonth,$BirthDay) = explode("-", $Birthdate);
// Find the differences
$YearDiff = date("Y") - $BirthYear;
$MonthDiff = date("m") - $BirthMonth;
$DayDiff = date("d") - $BirthDay;
// If the birthday has not occured this year
if (($MonthDiff < 0) || ($MonthDiff == 0 && $DayDiff < 0))
$YearDiff--;
return $YearDiff;
}
Shamelessly stolen from:Geekpedia
($MonthDiff >=0 && $DayDiff >= 0)nor
($DayDiff < 0 || $MonthDiff < 0)were taking all the math correctly into account. We managed to figure out something better.
Friday, February 5
Setting up DB2 for PHP on CentOS
Using a remote DB2 8.1 database with php 5.1.6 and Apache 2.2 on CentOS 5.4 (64 bit)
To download the IBM drivers for DB2, go to the IBM page and click on DB2 Client. If you don't have an account, you can request a free one. After logging in, download the IBM Data Server Client for linux. I also installed Express-C. I think this gave me some of the scripts I needed, though I'm not exactly sure. It was pretty self explanatory, download, extract, run the install script.
These instructions assume you've installed apache (httpd) via yum
# yum install php-pearwhen it asks for the installation dir, tell it: /opt/ibm/db2/dsdriver
# mkdir /opt/ibm/db2/
# cp ./ibm_data_server/opt/ibm/db2/
# cd /opt/ibm/db2
# tar -xzf ibm_data_server
# cd dsdriver
# sh ./installDSDriver
# pecl download ibm_db2
# pecl install ./ibm_db2
Now we set up php to use the driver.
# vi /etc/php.iniFind the section of Dynamic Extensions and add
extension=ibm_db2.soTo make sure it worked, run:
# php -i | grep -i db2and you should get some results like:
ibm_db2.... and so on
IBM DB2, Cloudscape and Apache Derby support => enabled
Binary data mode (ibm_db2.binmode) => DB2_BINARY
DB2 instance name (ibm_db2.instance_name) =>
PWD => /opt/ibm/db2/dsdriver
OLDPWD => /opt/ibm/db2/dsdriver/bin
So this is where I got stuck for a long time. At this point, db2_ commands will work from php, but it won't be able to find any database. All the documentation I read said things like "if you've created a db2 instance, point to it in your php.ini file" and stuff like that. It took me much longer to find how to actually create the instance.
Add the user db2inst1 (this is the default name php looks for an instance, but it can really be whatever.) I also put the user in a group I made (called db2grp1), but I don't think you need to.
# useradd db2inst1
# ./opt/ibm/db2/V8.1/instance/db2icrt db2inst1This creates the instance, which basically adds sqllib and bin dirs to the home directory, and changes the .bashrc. I also don't know where this script came from, maybe from Express-C.You can see all instances using:
# /home/db2inst1/sqllib/bin/db2ilistIf you want, you can go ahead and add this to the php.ini right now. I couldn't find anywhere that said where it had to be, so I just stuck it at the end before the end tag.
ibm_db2.instance_name=db2inst1This will update the results when you do a php -i|grep -i db2 as well.
Now we have an instance, php knows where it is, but the instance doesn't know where the database is. If you're on a local database, it's easy, but I'm not so I have to configure the local instance to go find the remote db.
su to the instance user.
# su db2inst1This created the alias to the server and to the database. Everything in italics should be your information. To test this has worked type
$ db2
=> catalog tcpip node remoteinst remote hostname.or.ip server 50000
=> catalog database testdb as remotedb at node remoteinst authentication server
=> terminate
=> connect to testdb user username using passwordYour connection should succeed and tell you database information:
Database Connection InformationIf it fails, it should tell you why.
Database server = DB2/6000 8.1.6
SQL authorization ID = USERNAME
Local database alias = TESTDB
SQL30082N Attempt to establish connection failed with security reason "24"Now we're almost done (finally). We just need to put the alias info into the db2dsdriver.cfg where php looks for it. To do this, there's another fancy IBM script, yay! This one should be in /opt/ibm/db2/dsdriver/bin, assuming you followed my instructions up above.
("USERNAME AND/OR PASSWORD INVALID"). SQLSTATE=08001
# cd /opt/ibm/db2/dsdriver/binThat should fill in the db2dsdriver.cfg file. It took mine a few tries to succeed, but I don't think i did anything differently, so I'm not sure why it was failing. If it keeps failing, try moving the script to /home/db2inst1/sqllib. Maybe I did that to make it work.
# ./db2dsdcfgfill -i db2inst1 -o /home/db2inst1/sqllib/cfg
One last thing before it'll work (and yes, I forgot this at first)
# httpd -k restartThat should be it. In php using the connection string, for the database, use the alias you created with the catalog commands.
<?phpResources:
$conn = db2_connect('testdb', 'user', 'password');
if (!$conn) {
echo "Connection failed.". db2_conn_errormsg();
}?>
php.net
IBM Library
db2ude
sqlrelay
and 100 more google search results
Anomaly:
Since the db2dsdriver can only be updated (in my experiences) using
db2dscfgfill -i db2inst1 -o /home/db2inst1/sqllib/cfgthat means the db2dsdriver located in /opt/ibm/db2/dsdriver/cfg will need to be updated manually. Even though php knows the instance is db2inst1, it still seems to look in the opt location for the driver. When I updated the driver, I just copied and overwrote the one in opt, then restarted the httpd server and all was fine. Before I overwrote the old one, it wasn't finding the alias.