What’s In Your Toolbox?
It’s going to be a long weekend…
With the help of my good friend Keith Crawford, I plan on reformatting my primary development machine today and doing a clean install of Windows 7. This project is long overdue, I can’t remember the last time I reformatted my drive, in fact this SATA drive that I am using now initially ran XP and then VISTA before I upgraded to WINDOWS 7 last year. Fortunately I am pretty diligent when it comes to backups, so the project isn’t as daunting as it could be.
Where to Start Reloading Software??
While preparing my plan of action last night I went through my list of installed software to see what I would need to reinstall once I got the OS reloaded. After going over the list I realized that I don’t use half of the programs that are installed on my machine. This got me to thinking, what else is out there that I might be missing out on? What tools / software do you use to develop client projects?
Here’s a list of the software and desktop applications that I use, please leave me a comment and let me know what you are using and if there is something on the market that I need to look at…
- Microsoft Outlook (Productivity) – Email, Calendars, Tasks, Notes, etc.
- Evernote Desktop (Productivity) – Notes.
- Microsoft Office Ultimate (Productivity) – Word, Excel, PowerPoint, etc.
- Microsoft Live Writer (Blogging) – WYSIWYG Blog Editor.
- Jasc Paintshop Pro (Graphics) – Lightweight compared to PS and faster for some jobs.
- Adobe Photoshop (Graphics) – All of the Bells & Whistles for Graphics.
- Adobe Illustrator (Vector) – I haven’t found anything else that compares for Illustrations.
- Adobe Dreamweaver (Code Editor / WYSIWYG) – My favorite WYSIWYG editor.
- Notepad++ (Code Editor) – Probably my favorite straight up code editor.
- Eclipse (Code Editor / IDE) – Rarely do I use this anymore.
- Xlinesoft PHPRunner (Code Editor / IDE / Generator) – Saves a ton of time
- Microsoft Expression Web (Code Editor / WYSIWYG) – Rarely do I use this anymore.
- Coda (Code Editor / WYSIWYG / CSS Editor) – Very nice but only works on my MacBook.
- TopStyle Pro (CSS Editor) – I haven’t found anything that compares
- IPSwitch WS-FTP Professional (FTP) – All of the Bells & Whistles for FTP
- Filezilla (FTP) – Fewer features than WS-FTP but a lot faster.
- Camtasia (Screen Capturing / Recording) – I haven’t found anything that compares.
- SwishMax (Flash / Vector Animation) – A lot faster than Flash to work with .SWF files.
- Audacity (Audio Editing / Recording) – I haven’t found anything that compares.
- Garage Band (Audio Editing / Recording) – Only works on my MacBook
- EZ Audio CD Ripper (Audio Editing / Ripping) – Fastest CD to MP3 Ripper I have found.
- Skype (Communications) – My favorite chat, voice, video conferencing app.
- RingCentral Call Controller (Communications) – Ties into our corporate phone system.
- SSH Explorer (SSH) – Rarely do I have to use this anymore because we have an admin.
- MySQL Administrator (Database) – I occasionally use this to connect to databases.
- TJPing (Ping) – I sometimes use this instead of command line.
- PuTTy (SSH, Telnet) – Rarely do I use this anymore because we have an admin.
PHPR Search Panel on _list.php?
I ran into something this evening using v5.2 of PHPRunner’s IDE / Code Generator that has me puzzled a bit. I have already brought it to Xlinesoft’s attention to inquire about the issue but haven’t heard back, and I have posted a message on the message board related to the issue as well. What is the issue? Well, it has to do w/ a way that I learned to code certain things in PHPRunner and I will be the first to go on record as saying that if there is one thing I have learned in life it is that “my way isn’t always the right way!”
I am pretty confident that the issue also has something to do w/ the new search panel in PHPR but I can’t be for certain though. Here’s what’s happening… Typically if I wanted to go to a table list page and place a URL link on a particular {$value} to be called in through a search on another list page I would just do something like this in the visual editor code view: (which is just a standard link URL w/ a value in it from the table.
<A href="http://www.arcb.net/referrals_database/business_directory_list.php?a=search&value=1&SearchFor={$row.1business_state_value}&SearchOption=Contains&SearchField=business_state">{$row.1business_state_value}</A>
Okay, well I tried doing this on my clients update project a few times and it kept messing up w/ me, I went back and checked my URL’s to make sure everything was correct w/ the syntax, etc., and couldn’t ever find out why my links kept breaking or didn’t form correctly. Well, long story short, here’s how I fixed the problem for now… Inside the Visual Editor I setup the value I was using to “view as” a hyperlink. Then I went into the hyperlink settings itself and put this in to define which list I wanted to search for my {$value} from.
state_associations_list.php?a=search&value=1&SearchOption=Equals&SearchFor=
I set this up as the URL prefix and told the Visual Editor to “Display Field Content” for the Value. Sure enough this worked, but what happened to make the old style of link building I was used to doing on the fly? I bet that it has something to do w/ the advanced search feature we just added. I am looking forward to hearing back from Sergey or Jane regarding the issue. I sure am glad that I wasn’t working on one of my Real Estate Clients database about the time I figured out my _list.php pages weren’t working anymore.
Now, if you should go this route for any reason here’s what you do. You just use the above line of code as your “hyperlink prefix” but be sure to swap out the “state_associations_list.php? w/ whatever list page you want to use. It should look something like the last box above when you paste it in…
Be sure to stay tuned to the Xlinesoft Forums for solutions to other problems.
Real Impressed w/ PHPR v5.2
I had a client that I did some application development for several years ago contact me this week for some routine maintenance to their solution. The project was simple enough, just building a dynamic URL w/ {$values_called_in} from the database. This custom URL would hit their existing search function and return their search results. Pretty straightforward. Since there were 4 tables total that this needed to happen with it only took me about 25 minutes to complete.
Since I have been so busy lately launching new projects I haven’t dabbled in very much PHP programming in a while so I welcomed this opportunity to get re-acquainted w/ PHPRunner so I downloaded the newest version 5.2 to check out all of the new functionality my friend Sergey has added since I last upgraded. I was amazed…
I have listed some of the newest additions in v5.2 below the video.
Since a lot of you might not have had the opportunity to play around w/ the newest version of the IDE I decided to record a screencast of my work on this client project, sans any sensitive data or logon information. I do realize I get around pretty fast in this IDE because it’s what I have been using for the past 4 years or longer, but hopefully just by glancing at the various screens within the project you can get a good comparison of PHPR versus whatever IDE / Code Generator you might currently be using.
Also, as a sidenote, I have already had one person request a “from start to finish” screencast on PHPR’s latest release and I hope to have that ready very soon. In the meantime, go pop some popcorn and grab yourself a soda and for the next 25 minutes what me upgrade this clients application for them.
Updates to PHPR v5.2 (changelog)
1. Audit Logon as admin/admin or user/user
All actions like login/logout/record editing/adding/deleting etc are logged to Audit table.2. Record locking. Logon as admin/admin or user/user
To test this feature open this project in two different browsers i.e. in Firefox and Chrome. Logon using different credentials and try to edit the same record in one of tables to see how it works. Admin is able to unblock record if it was blocked for too long or take ownership.
http://demo.asprunne…ect41/login.php3. Column resizing.
Resize any column on the list page by dragging it’s edge.4. Edit/Add master-details tables on the same page
View master and details (not implemented in this demo, will be available in final version)
multiple detail tables (nested or one master – many details). I.e. you can display customers, orders by customer, order details per order and edit all three tables at the same time without leaving the page. Sounds a bit crazy, huh?5. New FTP client. SFTP/FTPS support.
To increase upload speed change the number of FTP threads in Project->Settings.6. Option: Block user account after three unsuccessful login attempts
7. Option: Section 508 compliance
Check keyboard-based navigation through table links on the list page (Arrow Up, Arrow Down, Tab, Shift Tab).8. Search panel (advanced search on the list page)
Check search panel on the left. You can add new criteria. You can add the same field twice which will produce OR search (username=’admin’ or username=’test’). By default it implements ‘Contains’ search. To change this click ‘Show options’ link. You can use both search panel and simple search box at the same time. It produces AND search in this case. You can show/hide search panel clicking button with double arrows. You can also make search panel floating clicking pin button.9. Charts update.
Multiple series (unlimited), gauge charts (horizontal, vertical, circular), accumulation charts, scrollable charts, financial charts, bubble charts. Chart auto-refresh by specified time interval.
More info on new chart types:10. Google maps widget
Large map, ‘View as’ type ‘Map’ on List/View pages (separate map for each record), Clickable markers (point to the View page), javascript API to manage maps: map refresh on demand, center marker on map, add/update/delete markers11. ‘Insert button’ feature. Add a button in Visual Editor and type in code to be executed after button is pressed. Supports both client-side (Javascript) and server-side (PHP/ASP) events.
12. New databases support: Informix, DB2, SQLite, any ODBC-enabled
13. Add CAPTCHA to any page (Edit/Add/Login/Password reminder etc)
14. AJAX-based pagination/sorting/search
To turn this feature on proceed to ‘Choose pages’ screen and click ‘…’ button next to ‘List page’ check box.
By the way, if you are interested in checking out PHPRunner as a free trial download before you actually spend a couple hundred bucks on development software and generators, you can do so by visiting: http://www.xlinesoft.com/phprunner/?1057 and download your copy today!
Current Projects: Custom PHP/MySQL Members CMS
It’s been a long time since I actually coded a custom standalone php application for a client and I found my skills to be a little rusty at first. The reason I don’t get to code a lot of custom applications anymore is because most of the client projects we see today are built on top of a cms like wordpress or a framework like modx. In this instance the client already had their website developed internally and just needed us to develop an enhanced members area so they could communicate and share information with their members.
The membership table for this project has approximately 500 members in it, each member has the ability to authenticate by login and then view protected content. Members can also submit changes to their contact or login information that has to be approved before it’s accepted. Of course the normal features such as lost password restoration are also in place.

This solution was built entirely using PHP and all of the data is stored in 17 tables inside a MySQL database. For easier management of a large membership database with over 500 members, I also built in the ability to export and import data to the database from either XLS or CSV format. This should be another convenient aspect of the solution for our client.
I am pretty anxious to demo this application and bug-test it this next week. I used the newest version of PHPRunner IDE to develop this project and even though I was a little out of practice I still was able to code the project a lot faster than if I had used another tool like Eclipse or Notepad. The new version of PHPR is very nice, it’s been a while since I upgraded and have to admit that there are so many new features that I haven’t even looked into yet.
Locking Down Authentication Inside PHPRunner
One of the biggest challenges you face when building hosted applications is how to prevent brute force or guessed password authentications. Especially given the number of warez type applications that are out there that allow unsavory users to do just that. Well, I found a resource on Xlinesoft’s website that demonstrates how to do block a user after three unsuccessful attempts to login to your application.
This schema uses visitors IP address to store log attempts in the database and block access to to the login feature for 30 minutes after the third unsuccessful attempt. This schema involves Events function which is available in ASPRunnerpro 6.0/PHPRunner 5.0, I have reposted the processes involved for PHPRunner below, but you can find the ASPRunner notes here…
Step One:
In MySQL Server run the following script to create table in your database that logs login attempts. The box below demonstrates the MySQL command.
1: CREATE TABLE `LoginAttempts`
2: (
3: `IP` VARCHAR(20) NOT NULL,
4: `Attempts` INT NOT NULL,
5: `LastLogin` DATETIME NOT NULL
6: )
Step Two:
Open your PHPRunner project and go to the security tab and switch on the “Create Login Page” checklist.
Check the Username and password from database option and choose appropriate fields. If you have no table in which all of the login details are stored you have to create it.
Step Three:
Add three global events on the Events tab: BeforeLogin, AfterSuccessfulLogin, AfterUnsuccessfulLogin. Below you will find the PHPRunner example for this:
1: <?
2: function BeforeLogin($username, $password)
3: {
4: //********** Custom code ************
5: // check if this IP address is currently blocked
6: global $conn;
7: $sql = "select Attempts, LastLogin from LoginAttempts where ip = '" . $_SERVER["REMOTE_ADDR"] . "'";
8: $rs = db_query($sql,$conn);
9: $data = db_fetch_array($rs);
10:
11: if (!$data || !strlen($data["LastLogin"]))
12: return true;
13:
14: $atime = db2time($data["LastLogin"]);
15: $time = mktime($atime[3],$atime[4],$atime[5],$atime[1],$atime[2],$atime[0]);
16: $diff = (time()-$time)/60;
17:
18: if ($data["Attempts"]>=3)
19: {
20: if($diff<30)
21: {
22: echo "<p align=center><br><font color=red><b>Access denied for 30 minutes</b> <font></p>";
23: return false;
24: }
25: else
26: {
27: db_exec("update LoginAttempts set Attempts=0 where ip = '" . $_SERVER["REMOTE_ADDR"] . "'",$conn);
28: return true;
29: }
30: }
31: return true;
32: }
33:
34: function AfterSuccessfulLogin()
35: {
36: //********** Custom code ************
37: // clear previous attempts
38:
39: global $conn;
40: db_exec("update LoginAttempts set Attempts=0 where ip = '" . $_SERVER["REMOTE_ADDR"] . "'",$conn);
41:
42: }
43:
44: function AfterUnsuccessfulLogin()
45: //********** Custom code ************
46: // increase number of attempts
47: // set last login attempt timeif required
48: {
49: global $conn;
50: $sql = "select * from LoginAttempts where ip = '" . $_SERVER["REMOTE_ADDR"] . "'";
51: $rs = db_query($sql,$conn);
52: $data = db_fetch_array($rs);
53:
54: if($data)
55: {
56: $attempts = $data["Attempts"]+1;
57:
58: if($attempts==3)
59: db_exec("update LoginAttempts set Attempts=" . $attempts . ", LastLogin=now() where ip = '" .$_SERVER["REMOTE_ADDR"] . "'",$conn);
60: else
61: db_exec("update LoginAttempts set Attempts=" . $attempts . " where ip = '" .$_SERVER["REMOTE_ADDR"] . "'",$conn);
62: }
63: else
64: db_exec("insert into LoginAttempts (Attempts,IP,LastLogin) values (1, '".$_SERVER["REMOTE_ADDR"] . "',NOW())",$conn);
65: }
66: ?>
Step Four:
You should finish the code generation / compiling process and upload your application. It’s important to remember that by doing this, your visitors have to enter their username and password to gain access to the site. After the third unsuccessful login attempt, their IP addresses access will be denied for 30 minutes. When the visitor tries to login when the account is blocked they will see message saying access is denied.
Find out how to do this for ASPRunner also…
——————————————————————
There are a lot of other useful resources outlined for PHPRunner users in the Articles section on Xlinesoft’s website, you can find them here…
Facebook | PHPRunner User Group
I recently started a PHPRunner user group on Facebook in hopes of connecting with other PHPR programmers. So far we have 6 members, myself and of course Sergey, who is the CEO of the company that puts out PHPRunner, and four other guys. My main goal for creating the group was to provide some awareness of PHPRunner as well as being a way for PHPR developers to reach out to one another for paid assistance on projects built with PHPR. Honestly there have been times that I would have hired a developer to assist me on projects if he was familiar with PHPR.
Of course the formation of the group was met with a little opposition by users on the support forums because they didn’t see the need for such a group because the forums on xlinesoft’s website are already pretty active. I pointed out that there are user groups on Facebook for other IDE software clients such as CodeSmith, CodeCharge, and Eclipse and having a group for PHPR would probable help bring exposure to the product.
I also have always felt funny about soliciting developers from message boards, not to mention it’s forbidden on a lot of support forums, but having a Facebook group is perfect for something like this. I have made it very clear that the user group is not a support forum and is only intended for developers to network with one another, showcase their work, and to post projects for bid. I am hopeful that the group will grow in size and we can develop a pretty good community but I am also a realist and I know that PHPR users make up a pretty small piece of the pie. As I am sure a lot of you that have talked with me about PHPR already know, I am pretty hung up on this code generation thing and out of all the products I have seen on the market, PHPRunner is the best one out there.
If you are looking to learn more about PHPRunner, be sure to checkout their website.
AJAX for updating other fields
Here is a cool trick for utilizing AJAX to update other fields on pages inside of PHPR code. I have to thank Giles for pointing out calculation.js to me, see his notes below in this post.
The problem I wanted to solve was updating many price fields on a page as the user entered data in other fields using pricing information in a table not displayed at the time. The problem could be solved with a beforerecordupdated event but that would mean the user would have to save the record each time they wanted to see the price with subsequent impact on performance and usability.
The approach was to use AJAX responseXML. A javascript "calculation.js" gets the pricing data from "getdataxml.php", then performs the calc and displays the data on the user’s current page. The price data is only retrieved on the first execution of the script as it persists with the page. The script is executed whenever the fields involved in the calc are changed by the user.
calculation.js
1: var xmlHttp
2: var gotdata //used as flag so data only retreived once for each page call up
3:
4: // declare a var for each data element being read from the mysql table by the getdataxml.php page
5: // declared here so they persist for the life of the page
6: var id
7: var date_created
8: var date_modified
9: var pricefield
10:
11: //main function
12: //on first activation it sets up to get the data from mysql
13: //on subsequent activations it does the calculation...
14:
15: function docalcofsomesort(str)
16: {
17: xmlHttp=GetXmlHttpObject()
18: if (xmlHttp==null)
19: {
20: alert ("Browser does not support HTTP Request")
21: return
22: }
23: if (gotdata==null) //go get the data if not already done so...
24: {
25: alert ("Refreshing data") //just a footprint for debugging purposes
26: var url="getdataxml.php"
27: url=url+"?q="+str
28: url=url+"&sid="+Math.random() //the random element is attached to stop page caching on the server
29: xmlHttp.onreadystatechange=stateChanged
30: xmlHttp.open("GET",url,true)
31: xmlHttp.send(null) // ok, let's send the request and then wait for an answer...
32: }
33: else //if data already there do the calc...
34: {
35: alert ("Calculating") //just a footprint for debugging purposes
36: var newvalue = updatevalue()
37: document.getElementById("value_fieldwhereyouwantresult").value= newvalue; //store the result on the page...
38: }
39: }
40:
41: function stateChanged() //answer is back, let's grab the data
42: {
43:
44: if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")
45: {
46: xmlDoc=xmlHttp.responseXML;
47:
48: alert ("Storing data to variables") //just a footprint for debugging purposes
49: try
50: {
51: id = xmlDoc.getElementsByTagName("id")[0].childNodes[0].nodeValue;
52: date_created = xmlDoc.getElementsByTagName("date_created")[0].childNodes[0].nodeValue;
53: date_modified = xmlDoc.getElementsByTagName("date_modified")[0].childNodes[0].nodeValue;
54: anotherfield = xmlDoc.getElementsByTagName("pricefield")[0].childNodes[0].nodeValue;
55:
56: gotdata = 1;
57: alert("Stored data") //just a footprint for debugging purposes
58: docalcofsomesort("1") //recall the function to actually do the calc after getting the data
59: }
60: catch(err)
61: {
62: // with xml used in this way it's hard to know exactly what's going on as you can't directly
63: // see the returned data...the try-catch is an attempt to help trap missing data.
64: // could do with better error handling as it only helps a tiny bit. can get this alert for other
65: // reasons
66:
67: alert ("A value in the data has not been set up. Correct this and try again."+err.description)
68: }
69: }
70: }
71:
72: function GetXmlHttpObject() // this was just cut and paste from example. If you need
73: // explanation here you're on your own...
74: {
75: var objXMLHttp=null
76: if (window.XMLHttpRequest)
77: {
78: objXMLHttp=new XMLHttpRequest()
79: }
80: else if (window.ActiveXObject)
81: {
82: objXMLHttp=new ActiveXObject("Microsoft.XMLHTTP")
83: }
84: return objXMLHttp
85: }
86:
87: function updatevalue() // here's the function that actually does the calculation
88: // insert your own here...simple example below
89:
90: {
91: var initvalue = 0
92: initvalue += document.getElementById("value_some_field_qty").value*anotherfield
93: ...and whatever else needs to be calculated....
94:
95: return initvalue
96: }
97:
98: function setupthepageforcalc() //fields where results will be displayed are editable text fields in phprunner
99: // but are disabled and colour highlighted so user cannot change them.
100: // fields used in the calcs have their onchange event set so they trigger the calc
101: {
102: color = "#F1F1F1"; // used later down for distinguishing these fields
103:
104: // make the following fields shaded and disabled so user cannot edit them
105: document.getElementById("value_fieldwhereyouwantresult").disabled=1;
106: document.getElementById("value_fieldwhereyouwantresult").style.background = color;
107:
108: // make the following fields execute the calc onchange...
109: document.getElementById("value_some_field_qty").onchange = function() {docalcofsomesort("13");};
110: }
111:
112: function submitform() //in order to save the calculated resluts in the data base must enable fields
113: {
114: alert("Saving"); // another footprint
115: document.getElementById("value_some_field_qty").disabled=false;
116: document.editform.submit();
117: }
getdataxml.php:
1: <?php
2: header('Content-Type: text/xml');
3: header("Cache-Control: no-cache, must-revalidate");
4: //A date in the past
5: header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
6:
7: $q=$_GET["q"];
8:
9: $con = mysql_connect('localhost', 'user', 'yourpassword');
10: if (!$con)
11: {
12: die('Could not connect: ' . mysql_error());
13: }
14:
15: mysql_select_db("mysql database", $con);
16:
17: $sql="SELECT * FROM yourtable WHERE ID = ".$q."";
18:
19: $result = mysql_query($sql);
20:
21: echo '<?xml version="1.0" encoding="ISO-8859-1"?>
22: <dataset>';
23: while($row = mysql_fetch_array($result))
24: {
25: echo "<id>" . $row['ID'] . "</id>";
26: echo "<date_created>" . $row['Date_Created'] . "</date_created>";
27: echo "<date_modified>" . $row['Date_Modified'] . "</date_modified>";
28: echo "<anotherfield>" . $row['anotherfield'] . "</anotherfield>";
29: }
30: echo "</dataset>";
31:
32: mysql_close($con);
33: ?>
Additional Points by Giles:
1. Each field involved in the calculation or the results must have an id attribute. I used text fields only and modified the include/commonfunction.php to generate the id for editable text fields by inserting id="’.$cfield.’" in the second echo statement as shown below. (Admin, could we have this in the standard product??)
1: if($format==EDIT_FORMAT_TEXT_FIELD)2: {3: if(IsDateFieldType($type))4: echo '<input type="hidden" name="'.$ctype.'" value="date'.EDIT_DATE_SIMPLE.'">'.GetDateEdit($field,$value,0,$secondfield,$edit);5: else6: {7: if($edit==MODE_SEARCH)8: echo '<input type="text" autocomplete="off" name="'.$cfield.'" '.GetEditParams($field).' value="'.htmlspecialchars($value).'">';9: else10: echo '<input type="text" name="'.$cfield.'" id="'.$cfield.'" '.GetEditParams($field).' value="'.htmlspecialchars($value).'">';2. The javascript was added in the header section of the _edit page via the Visual Editor in html mode
1: <script> src="calculation.js" </script>3. Activation of setupthepageforcalc() was done by adding the following line just above the Save/Back To List buttons
1: <script type="text/javascript"> setupthepageforcalc() </script>This function needs to be executed each time the page is displayed to disable the results fields
4. The submitform() function needs to be activated when the page is saved so the onclick event of the save button was modified:
1: onclick=submitform()
For simplicity sake I’ve simplified the amount of data being retrieved and the number of calculations and results fields. also inserted comments and changed a few field/field names to protect the guilty. So be on the lookout for any errors.
Also I created a php page to help create some repetitive parts of the code (e.g. var decarations in the javascript) where multiple fields are involved. Just run the following php and copy/paste as needed. Note the GoodFieldName() function is from phprunner but also forces the goodfieldname to lower case. I thought javascript would not like upper case…
1: <?php
2:
3: //Create the field data section of the getdataxml.php file
4:
5: $con = mysql_connect("localhost", "user", "your password");
6: if (!$con)
7: {
8: die('Could not connect: ' . mysql_error());
9: }
10:
11: $db_selected = mysql_select_db("mysql database",$con);
12:
13: $sql = "SELECT * from your table";
14: $result = mysql_query($sql,$con);
15:
16: $donetablename=0;
17: while ($property = mysql_fetch_field($result))
18: {
19: If ($donetablename==0)
20: {
21: echo "Table name: " . $property->table . ". Entries for xml.php file<br />";
22: $donetablename = 1;
23: }
24: $fieldname = GoodFieldName($property->name);
25: $str = "echo \"<".$fieldname.">\" . row['".$property->name."'] . \"</".$fieldname.">\";";
26: echo htmlspecialchars($str)."<br>";
27:
28: }
29:
30: echo "<br>";
31: echo "<br>";
32: echo "<br>";
33:
34: $result = mysql_query($sql,$con);
35:
36: $donetablename=0;
37: while ($property = mysql_fetch_field($result))
38: {
39: If ($donetablename==0)
40: {
41: echo "Table name: " . $property->table . ". var entries for js file<br />";
42: $donetablename = 1;
43: }
44: $fieldname = GoodFieldName($property->name);
45: $str = "var ".$fieldname;
46: echo htmlspecialchars($str)."<br>";
47:
48: }
49:
50: echo "<br>";
51: echo "<br>";
52: echo "<br>";
53:
54: $result = mysql_query($sql,$con);
55:
56: $donetablename=0;
57: while ($property = mysql_fetch_field($result))
58: {
59: If ($donetablename==0)
60: {
61: echo "Table name: " . $property->table . ". getElementsByTagName entries for js file<br />";
62: $donetablename = 1;
63: }
64: $fieldname = GoodFieldName($property->name);
65: $str = $fieldname." = xmlDoc.getElementsByTagName(\"".$fieldname."\")[0].childNodes[0].nodeValue;";
66: echo htmlspecialchars($str)."<br>";
67:
68: }
69:
70: mysql_close($con);
71:
72:
73: // construct "good" field name
74: function GoodFieldName($field)
75: {
76: $field=(string)$field;
77: for($i=0;$i<strlen($field);$i++)
78: {
79: $t=ord($field[$i]);
80: if(($t<ord('a') || $t>ord('z')) && ($t<ord('A') || $t>ord('Z')) && ($t<ord('0') || $t>ord('9')))
81: $field[$i]='_';
82: }
83: $field = strtolower($field);
84: return $field;
85: }
86:
87: ?>
If someone knows of a better way to approach this or suggestions how to improve or make this simpler, please feel free to comment on the forums: Using AJAX for updating other fields on pages – Forums
Pulling URL from _table_search.php
If you are using PHPR (phprunner) as your IDE to develop your PHP applications in here’s a trick that you are likely going to appreciate at some point in your coding career.
If you utilize the advanced search feature in your applications (not the standard inline search, but the advanced search) and you would like to be able to find the URL for your advanced search results page (with multiple fields included) here’s a way to do it in both PHPR 4.2 and PHPR 5.0. Both of these are provided by Jane at Xlinesoft on the Tips and Tricks forum:
You will first want to pull up your advanced search page {_table_search.php} inside the visual editor regardless of which version you are using.
PHPR 4.2
Switch out this line of code:
1: <form method="POST" action="TableName_list.php" name="editform">
and replace it with this line of code:
1: <form method="GET" action="TableName_list.php" name="editform">
PHPR 5.0
Switch out this line of code:
1: $contents_block["begin"]="<form method=\"POST\" ";
and replace it with this line of code:
1: $contents_block["begin"]="<form method=\"GET\" ";
Adding Form to DB Record in PHPR
I recently had a pretty intensive PHPR project where I had to create a page for a client that called in records from their database as well as displaying a form that visitors could us to contact the “name” and “email” from that particular record. In theory this isn’t a complicated thing to get your mind around but I found that building this in PHPR *PHPRUNNER) was going to be a task for a couple of reasons.
I have had a fellow PHPR user drop me a note and ask me to document how I put all of this together so I figured I would do so here. I am going to prepare some documentation later on regarding two aspects of this project and post them to the PHPR forums later once I have a chance to document everything a little bit better…
The biggest thing that I ran into was issues with Smarty Templates and just inserting a standard PHP Form into them, that was a no-go all the way around for the most part, I did stumble on some ways to do this if anyone is interested but I ultimately didn’t use this on this project. I went back and forth with Jane from Xlinesoft for a while and she was awesome in helping get my mind around this, she also really helped me out a lot with some javascript features that the client was wanting to have with their photo gallery. Xline is awesome! If you build web portals with PHP/MySQL you owe it to yourself to checkout PHPR!
Here’s how I was able to get this particular process to work. I created a new table in the database to store the visitors (people requesting information) information in. I set my permissions so that public could hit this form and store data into it (with validation). Once I created this table and generated it’s add page in PHPR I then went and added that code to the already generated view page from PHPR of the records that I wanted to also have this form on. I then coped my form code into the view page at the appropriate place and saved it out. It took a little while inside the visual editor’s code view to get this to work exactly right but I eventually was able.
The very next part was probably the trickiest to figure out inside of PHPR because if you are familiar with PHPR you will know that you primarily are working with generated smarty pages. In order to add some logic to the form I added this event code in the event editor, (after record added)
1: // Parameters:
2: // $values - Array object.
3: // Each field on the Add form is represented as a 'Field name'-'Field value' pair
4: // $keys - Array object with added record key column values
5: // target_email and target_name are called from the existing database
6:
7:
8: //********** Send email with new data ************
9:
10: $email="".$values["target_email"];
11: $message="";
12: $subject="Resort Inquiry - ".$values["target_name"];
13: $from="Client's Name <info@clientsdomain.com>";
14:
15: foreach($values as $field=>$value)
16: $message.= $field." : ".$value."\r\n";
17:
18: //Headers
19: $headers = "To: " . "\r\n";
20: $headers.= "From: $from" . "\r\n";
21:
22: mail($email, $subject, $message, $headers);
23:
24:
25: //********** Redirect to another page ************
26: header("Location: http://www.clientsdomain.com/confirmation.php");
27: exit();
After I added this and tested the form it was working great. Here is something that I probably need to make sure I mention. In my trials building this particular app, I learned that i had to go in and predefine the value for 2 hidden fields in the form, one was the “name on the record” and the “email on the record”. Once i had this part knocked out everything worked great. This is pretty good to know because there wasn’t a whole lot of information on the forums when I started trying to build this particular app and I had to hunt around and find info from various places. As I mentioned, Jane at Xlinesoft was awesome to help me out with this project.
PHPR Project Management
I found this interesting post on the Xlinesoft forum tonight. (Best Practices) It relates to Best Practices for using PHPRunner & Subversioning. I currently don’t have a use for this in anything I am working on but thought that it was pretty interesting so I decided to include it here…
——————————————————
1.0 Summary:
Setting up an SVN Repository significantly increases manageabilty of large scale projects using PHPRunner across many environment instances and developers. SVN Repository will also encourage companies to use PHPRunner to be used in larger scale projects. The output codes can be deployed based on the subversions and the config file can be determiend upon staging.
2.0 Case Statement
I have a project that is used in the development and live environment. Initially, it was not an issue since the db schema was synched. As the the dev version is release to production, and additional tables were added to the dev environment, I found it almost impossible to manage the project with my simplistic approach. What I ended up doing was for each instance of the development (dev, test, stage and live), I created seperate projects. so, I now have 4 individual projects. Our european counterpart saw our US project and of course, they requested for each of their instances which of course was about 6 all together. So, now I have a total of 10 seperate project for each db instance of our development phase. In my mind, the only difference is the config (i.e., host, user, password and db name).
For awhile, I would just select one of the projects, make my modifcations, and then save as for each instance of the project. This worked for awhile.The problem started to occur when we went live the first time. There were enhancements that I wanted to make for the production version. Meanwhile, the db schema in the development and test instances started to change. So, I found many of my links started to break. So, I could no longer just simply Save As. The next step was to Cut and Paste.
I stopped Saving As, and started doing the following. I would make the changes in one of the most complete instance which usually was the development instance since its where the new tables are comming from. Then, I would open another PHPRunner and open one of the other instances that I wanted to update. Of course, I couldn’t update all since some of the test and stage instances have not been updated.As a result, there was chaos in my codes. I no longer didn’t remember which project belonged to what instance. I didn’t know which one got updated and which ones are the same and which ones are broken. In other words, the project(s) became extremely unmanageable.
3.0 Analysis
This is a typical result when what seemed to be an easy process ended up entangled. Many times, the simpliest approach many not be the wisest approach and could cause havoc on project and resource management. The criteria for a simple project is if the proejct is being developed by a single develper on one or two instance of the same project. Both db instance must be synched for most of the time or at least a push to keep it in synched. As soon as a third unsycnronized db instance is introduced, then it can no longer be considered as a simple project management case. In order to avoid the pitfall of the case statement, one must ensure scalability, flexibility of code management, as well as the deploy process.
4.0 Approach
4.1 Set-up
The way to resolve the issue was we deployed a subversioning tool, SVN with a UI frontend, Tortoise. We created a project folder in the SVN Repository and a trunc.
I selected the best “version” from the projects, which we’ll call ProjectPHP. I then looked for the PHPR project file and copied that and the tmp and visual folders into my SVN trunc folder (which was also in my local apache htmdoc webserver path). I opened PHPRunner, make the changes I wanted and Save. I am now saving the PHPR file into my SVN trunc folder that is also within my apache webserver folder. I set my output file directly onto my trunc folder and I set the preview with the localhost url. I build the projects.4.2 Work Process and Project Management
If all goes well, all the output files is created within the trunc folder. I use the preview just to see if anything was broken. When I am satisfied with the changes, I close PHPRunner and then go to the trunc folder. I delete the tmp and visual folder since I discovered that once I successfully build an output files with the tmp and visual folders, I can erase those two folders. Somehow, when I open PHPRunner and build it again, PHPRunner knows where to look for those tmp and visual folders. Also, for some reason even if I delete these folders, when I go to my Visual Editor, I can still see all the icons.
I committ all the files to the SVN Repository. (Note: It’s realy easy to do it using Tortoise SVN). I know have a trunc of my project. I then check out a Working Copy. This is a good idea since you don’t want to mess up your trunc version since it will always be your “base copy” of the code. In my working copy, I can open PHPRunner and open that particular project file. It works beautifully. All the icons show up in my visual editor. I can change the db configuration so that I am developing to the relevant instance of the database. Once I am done, I save my I used the Live instance of db to create or update the project. Once I was satisfied, I save my project which was the latest and greatest of the codes that I have been chaotically managing. Once we created the trunc, we created tags and branches.
I checked out the trunc into my Working Copy folder. For now, my WC is pointed towards the trunc. For every major milesone I reach, I create a Tag. The naming convention for the tag is usually the date and some task indicator like Dec102008_Task_1of3 or some other meaningful naming convention. I continue with my work on my WC until I complete all my tasks. By now, I have 3 tags, since I created them for each milestone.
I then committ my changes into the SVN Repository. Since I was pointed towards the trunc, it updated the Trunc. But since it is also a completion of a version of ProjectPHP, I created a Branch and called it Revision 1.0. This is my first “subversion.”
For now, I can continue to make small modificaitons or bug fixes to Revision 1.0. It is important to note that I am working constantly on my WC (Working Copy). Basically, I can “Switch” the WC to the trunc, tags or branches. When I am working on Revision 1.0, I will make tags along the way in order not to lose any of my codes in cases I mess up further along the way. There is a stopping point. Once I am done with my changes, I create a subversion Revision 1.1
Note: Please refer to the sources link below for more detailed subversion workflow.
4.3 Deployment
For every completed revision, I test it in the Test, QA, Stage environment. And once it passes all 3, then I deploy it to Production. We created a page that allowed me to selecte which subversion I want to deploy and the “dbcommon” version that I want to use. Since in PHPRunner, the db information is part of the editing the project, when it builds the file, it also builds the dbcommon that has all the db information (user, password, etc.). So, when there is a different db login for each instance, you will have to specify the correct “version” of the dbcommon. All I did was to create one dbcommon as a “trunc” and then created all versions of that for each instance of the db.
Whenever I deploy, I select the code that I wanted to put into dev, qa or stage, and select the appropriate dbcommon. It is a dropdown. The staging process basically takes all my files which are the output files and overrides the dbcommon with whatever “version” of the file I select. Remember the version is realy just to be able to have all the dbcommon for all the instances.
Also, there is one caveats for those that may want to have a others use the project for each of the instance. So, say if you have a Live version with the old db schema. So the Live version is Revision 1 and all the subversions. The active development is already on Revision 3, for example. And you’ve made some changes on Revision 3 and deployed it to your develpment and stage instances (and not Live of course, because the latest db has not been deployed to Live).
Since you still want to test and stage your Revision 1 code, you can deploy the codes to the development and test environments but use the db instance that has the matching schema (usually by now, it will be just the Live version). Notify the folks using the tool that you’ll be testing and staging a production fix and therefore need to log out. Once you verify in test and stage the codes, deploy the code to Live. At this point, unless there are major functionality and not just small fixes, you may have to merge it with either Revision 3 (the latest and greatest version of your project) or back to the Trunc.
I suggest not to do this however. I would just leave Revision 1 and all its subversions where it is. It is easier just to make sure that that functionality is copied over to Revision 3 and then merged back to the trunc (since Revision 4 may be under way).
5.0 Conclusion
When you use SVN with Tortoise and set up the appropriate subversions, your project with multiple developers and instances can be manageable, as long as everyone understands the subversioning principle. Keep the PHPR file with the output files and delete the tmp and visual folders once you have successfully built a project within the svn file folder. The PHPR file gets subversioned as well. In other words, it becomes protected for any accidental mistakes (like I have done so many times with my manual management of my php projects.)
I hope this post will encoruage to use PHPRunner at a large scale basis and will encourage the makers of PHPRunner to make it more and more robust.6.0 To Do’s
- Set up URLs for each project intance (dev, test, stage, live). These corresponds to the db instances.
- Set up SVN repository
- Set up staging page. There will be a list of the environment where the codes will be deployed, a list of the code version to deploy, and the dbcommon version to override the dbcommon built along with the PHPRunner.
- Set up Project Folder then /trunc, /tags, /branches (Please see the link and study the manuals)






