The Perfect Job - Part 2

Unfinished Business

In the first part of this article, I explained some of the problems typically associated with data management in a HR department, and put together a functional specification for a Web-based application to make the task easier. After putting together a basic database schema and normalizing it, I proceeded to develop scripts to display job listings, accept user applications, and store these applications in the database.

While the first part of this article described the user experience, I have not yet addressed the issues of updating the job board with new information, removing existing entries, or searching for potential candidates – all of which formed part of the initial feature set of this application. And so, in this concluding article, I’m going to wrap things up by looking at some of the tasks an administrator would need to accomplish in such a system, and developing some simple scripts to accomplish these.

Administrator Ahoy!

If you remember, when I first put together the "listings" table, I added a couple of dummy entries to it, just to get things rolling.

Now, that’s fine during the early stages of application development… but you can’t expect your customers to pop open a mySQL prompt every time they need to update a job listing. For one thing, they may not have the technical acumen necessary to manipulate a mySQL database; for another, they may prefer a pretty GUI to an ugly command-line. Either way, as the developer, you’re on the hook to package those functions into your application as well.

Consequently, I’ll begin by putting together an entry point for administrators, in much the same way as I did for users. This page will serve as a menu to the different administration functions available.

<?   // admin.php - admin functions entry point  // includes 

// open connection to database  $connection = mysql_connect($hostname, $user, $pass) or die   ("Unable to connect!"); 

// get list of departments with open jobs  $query = "SELECT DISTINCT id, department from department, listing WHERE   department.id = listing.fk_department";  $result = mysql_db_query($database, $query, $connection) or die ("Error   in query: $query. " . mysql_error()); 

// generate a table  echo "<table border=0 cellspacing=5 cellpadding=5>"; 

// iterate through resultset  while(list($id, $department) = mysql_fetch_row($result))  { 

// print department name  echo "<tr><td colspan=4><b>Department:</b> $department</td></tr>"; 

// look for jobs within the department and print as list,   add edit and delete links  $query2 = "SELECT jcode, designation from listing WHERE   listing.fk_department = '$id'";  $result2 = mysql_db_query($database, $query2, $connection) or die   ("Error in query: $query2. " . mysql_error());  while(list($jcode, $dsg) = mysql_fetch_row($result2))  {  echo "<tr><td width=10>&nbsp;</td><td>$dsg ($jcode)</td>   <td><a href=edit.php?jcode=$jcode>  <font size=-1>edit</font></a></td> <td><a href=delete.php?jcode=$jcode>  <font size=-1>delete</font>  </a></td></tr>";  }  }  echo "</table>";  ?>  <!-- snip --> 

<a href="add.php">Add a new listing</a> or <a href="search.php">search   the database</a> 

<!-- snip -->

Here’s what it looks like.

The Perfect Job - Part 2

As you can see, it’s almost identical to the user entry point, with the exception of the edit and delete links next to each job. Each of these calls a script to perform the appropriate function. The bottom of the page also includes links to add a new listing, or search the database for potential candidates.

It should be noted at this point that access to all these administration scripts should be restricted to privileged users only. The easiest way to do this is to move them into a separate directory, and protect it using Web-based authentication.

Copyright Melonfire, 2000. All rights reserved.

Adding To The Mix

The script "add.php" display a form which allows an administrator to add a new job listing to the system. The script is divided into two sections – one section displays a form, while the other section processes the data entered into it. The $submit variable is used to decide which section of the script to execute.

<?   // form not yet submitted   if (!$submit)   {   // open connection to database   $connection = mysql_connect($hostname, $user, $pass) or die   ("Unable to connect!");   ?>   <table border="0" cellspacing="5" cellpadding="2">   <form action="<? echo $PHP_SELF; ?>" method="POST">   <!-- input job details -->   <tr>   <td>Job code<font color="red">*</font></td>   </tr>   <tr>   <td><input type="text" name="jcode" size="10" maxlength="10"></td>   </tr>   <tr>   <td>Designation<font color="red">*</font></td>   <td width=30>&nbsp;</td>   <td>Department<font color="red">*</font></td>   </tr>   <tr>   <td><input type="text" name="dsg" size="25"></td>   <td width=30>&nbsp;</td>   <td><select name="dpt">   <?  

// get department list   $query = "SELECT id, department from department";   $result = mysql_db_query($database, $query, $connection) or die    ("Error in query: $query. " . mysql_error());   while (list($id, $department) = mysql_fetch_row($result))   {   echo "<option value=$id>$department</option>";   }   mysql_free_result($result);   ?>   </select></td>   </tr>   <tr>   <td>Location<font color="red">*</font></td>   <td width=30>&nbsp;</td>   <td>Salary<font color="red">*</font></td>   </tr>   <tr>   <td><select name="loc">   <?  

// get location list   $query = "SELECT id, location from location";   $result = mysql_db_query($database, $query, $connection) or die    ("Error in query: $query. " . mysql_error());   while (list($id, $location) = mysql_fetch_row($result))   {   echo "<option value=$id>$location</option>";   }   mysql_free_result($result);   ?>   </select></td>   <td width=30>&nbsp;</td>   <td><select name="sal">   <?  

// get salary list   $query = "SELECT id, salary from salary";   $result = mysql_db_query($database, $query, $connection) or die    ("Error in query: $query. " . mysql_error());   while (list($id, $salary) = mysql_fetch_row($result))   {   echo "<option value=$id>$salary</option>";   }   mysql_free_result($result);   mysql_close($connection);   ?>   </select></td>   </tr>   <tr>   <td>Responsibilities<font color="red">*</font></td>   <td width=30>&nbsp;</td>   <td>Qualifications<font color="red">*</font></td>   </tr>   <tr>   <td><textarea name="rsp" cols="40" rows="8"></textarea></td>   <td width=30>&nbsp;</td>   <td><textarea name="qlf" cols="40" rows="8"></textarea></td>   </tr>   <tr>   <td>Contact person<font color="red">*</font></td>   <td width=30>&nbsp;</td>   <td>Email address<font color="red">*</font></td>   </tr>   <tr>   <td><input type="text" name="cname" size="25"></td>   <td width=30>&nbsp;</td>   <td><input type="text" name="cmail" size="25"></td>   </tr>   <tr>   <td align=center colspan=3><input type=submit    name=submit value="Add Listing"></td>   </tr>   </table>   </form>   <?   }   else   {  

// form submitted, process it   }   ?>

Here’s what it looks like.

The Perfect Job - Part 2

Nothing too complicated here – this is simply a form, with text fields for some elements of the job listing, and drop-down boxes for the remainder. You will notice that the items in the drop-downs are generated from the database; you probably remember this from last time.

Notice also the ACTION attribute of the <FORM> tag, which is pointing to a PHP variable called $PHP_SELF. This is a built-in PHP variable which always holds the name of the currently-executing script; by including it here, I am ensuring that the same script is also called to process the form.

Once the form is submitted, the same script is called again; however, since the $submit variable will now exist, the second half of the script springs into action.

<?   // form not yet submitted   if (!$submit)   {  

// generate form   }   else   {  

// form submitted, process it   // set up error list array   $errorList = array();   $count = 0;  

// validate text input fields   if (empty($jcode)) { $errorList[$count] = "Invalid entry: Job code";    $count++; }   if (empty($dsg)) { $errorList[$count] = "Invalid entry: Designation";    $count++; }   if (empty($rsp)) { $errorList[$count] = "Invalid entry:    Responsibilities"; $count++; }   if (empty($qlf)) { $errorList[$count] = "Invalid entry: Qualifications";    $count++; }   if (empty($cname)) { $errorList[$count] = "Invalid entry: Contact name";    $count++; }   if (empty($cmail) || isEmailInvalid($cmail)) { $errorList[$count] =    "Invalid entry: Email address"; $count++; }   if (sizeof($errorList) == 0)   {  

// open connection to database   $connection = mysql_connect($hostname, $user, $pass) or die    ("Unable to connect!");  

// insert data   $query = "INSERT INTO listing (jcode, designation, responsibilities,    qualifications, cname, cmail, posted, fk_department, fk_location,    fk_salary)    VALUES ('$jcode', '$dsg', '$rsp', '$qlf', '$cname', '$cmail',    NOW(), '$dpt', '$loc', '$sal')";   $result = mysql_db_query($database, $query, $connection) or die    ("Error in query: $query. " . mysql_error());  

// clean up   mysql_close($connection);   echo "Entry successfully added.<p><a href=$PHP_SELF>Add    another entry</a>, or    <a href=job_list.php>return to job listings</a>";   }   else   {   listErrors();   }   }   ?>

The error-checking mechanism used here should be familiar to you from the job application form in the previous article… although the validation routines here are a little simpler, since this form is far less complex.

Once the data has been validated and found to be acceptable, an INSERT query takes care of saving the data to the "listing" table, so that it immediately appears on the job listing page.
Copyright Melonfire, 2000. All rights reserved.

Changing Things Around

The "edit.php" script is almost identical; it accepts a job listing, connects to the database, retrieves the record, and displays a form with the values filled in. The administrator can now update the listing and save it back to the database.

<?    // edit.php - edit job listing    // form not yet submitted    if (!$submit)    {   

// open connection to database    $connection = mysql_connect($hostname, $user, $pass) or die     ("Unable to connect!");   

// get job details    $query = "SELECT designation, jcode, fk_department,     fk_location, fk_salary, responsibilities, qualifications,     cname, cmail from listing WHERE jcode = '$jcode'";   

// snip    list($designation, $jcode, $department, $location,     $salary, $description, $qualification, $cname, $cmail,    $posted) = mysql_fetch_row($result);   

// display form with values pre-filled    ?>    <!-- snip -->   

<table border="0" cellspacing="5" cellpadding="2">    <form action="<? echo $PHP_SELF; ?>" method="POST">    <input type=hidden name="jcode" value="<? echo $jcode; ?>">    <!--  job details -->   

<tr>    <td>Designation<font color="red">*</font></td>    <td width=30>&nbsp;</td>    <td>Department<font color="red">*</font></td>    </tr>   

<tr>    <td><input type="text" name="dsg" size="25" value="<? echo     $designation; ?>"></td>    <td width=30>&nbsp;</td>    <td><select name="dpt">    <?   

// get department list    $query = "SELECT id, department from department";    $result = mysql_db_query($database, $query, $connection) or die     ("Error in query: $query. " . mysql_error());    while (list($id, $dpt) = mysql_fetch_row($result))    {    echo "<option value=$id";   

// pre-select value    if ($id == $department)    {    echo " selected";    }    echo ">$dpt</option>";    }    mysql_free_result($result);    ?>    </select></td>    </tr>    <!-- and so on -->   

<tr>    <td align=center colspan=3><input type=submit name=submit     value="Update Listing"></td>    </tr>    </table>    </form>    <?    }    else    {   

// form submitted, process    }    ?>

Once the form has been submitted, an UPDATE query is executed to update the database with the new information.

<?    // form not yet submitted    if (!$submit)    {   

// generate form    }   

// form submitted, process    else    {   

// set up error list array    $errorList = array();    $count = 0;   

// validate text input fields    if (sizeof($errorList) == 0)    {   

// no errors    // open connection to database    $connection = mysql_connect($hostname, $user, $pass) or die     ("Unable to connect!");   

// update data    $query = "UPDATE listing SET designation='$dsg',     responsibilities='$rsp',     qualifications='$qlf', cname='$cname', cmail='$cmail',     fk_department='$dpt', fk_location='$loc', fk_salary='$sal' WHERE     jcode='$jcode'";    $result = mysql_db_query($database, $query, $connection) or die     ("Error in query: $query. " . mysql_error());   

// clean up    mysql_close($connection);   

// redirect    header("Location:admin.php");    }    else   

// errors, display    {    listErrors();    }    }    ?>

The "delete.php" script is the simplest of the lot. It accepts a job code, connects to the database, DELETEs the appropriate records, and redirects the browser back to the menu.

<?    // delete.php - delete job listing    // includes and error checks    // open connection to database    $connection = mysql_connect($hostname, $user, $pass) or die     ("Unable to connect!");   

// delete record    $query = "DELETE FROM listing WHERE jcode = '$jcode'";    $result = mysql_db_query($database, $query, $connection) or die     ("Error in query: $query. " . mysql_error());    mysql_close($connection);   

// redirect    header("Location:admin.php");    ?>

Just as I have these scripts to alter the "listing" table, you can develop additional scripts to modify the other ancillary tables – "country", "salary" et al – if you like. That said, it should be noted that not all the tables will change on a regular basis (for example, how often are you likely to update the list of countries?) Some tables will be set up with an initial set of records, and will remain unchanged for long periods of time, while others may change on a weekly basis; as the developer, it’s up to you to anticipate the likely requirements of the customer, and develop administration modules appropriately.

Copyright Melonfire, 2000. All rights reserved.

Desperately Seeking Perl Guru

Next up, the search function. This is probably the most-used function in this type of system, since it allows administrators to quickly extract a set of applications which match pre-defined criteria. As before, the script has two sections, one for the form and the other for the processor.

<?      // search.php - search for specific applications     // includes     // open connection to database     $connection = mysql_connect($hostname, $user, $pass) or die      ("Unable to connect!");     if(!$submit)     {    

// form not yet submitted, display form     ?>     <html>     <head>     <basefont face="Verdana" size="2">     </head>     <body bgcolor=white>     <? $image="search.jpg"; ?>     <? include("header.inc.php"); ?>     <form action="<? echo $PHP_SELF; ?>" method="post">     Display all applications for the post      <select name="jcode">     <?    

// get list of open jobs     $query = "SELECT DISTINCT jcode, designation from listing";     $result = mysql_db_query($database, $query, $connection) or die      ("Error in query: $query. " . mysql_error());    

// and print     while(list($jcode, $designation) = mysql_fetch_row($result))     {     echo "<option value=$jcode>$designation ($jcode)</option>";     }     mysql_free_result($result);     ?>     </select>     <p>     <ul>     <li>with skills matching the keywords     <input type=text name=skills size=35>     <p>     and experience      <select name=exp_modifier>     <option value="">&lt;unspecified&gt;</option>     <option value="=">equal to</option>     <option value=">=">greater than or equal to</option>     <option value="<=">less than or equal to</option>     </select>     <input type=text name=years size=2 maxlength=2>     years     <p>     <li>with educational qualifications equivalent to     <select name="degree">     <option value="">&lt;unspecified&gt;</option>     <?    

// get list of degrees     $query = "SELECT id, degree from degree";     $result = mysql_db_query($database, $query, $connection) or die      ("Error in query: $query. " . mysql_error());     while(list($id, $degree) = mysql_fetch_row($result))     {     echo "<option value=$id>$degree</option>";     }     mysql_free_result($result);     ?>     </select>     in     <select name=subject>     <option value="">&lt;unspecified&gt;</option>     <?    

// get list of subjects     $query = "SELECT id, subject from subject";     $result = mysql_db_query($database, $query, $connection) or die      ("Error in query: $query. " . mysql_error());     while(list($id, $subject) = mysql_fetch_row($result))     {     echo "<option value=$id>$subject</option>";     }     mysql_free_result($result);     ?>     </select>     </ul>     <center>     <input type="submit" name="submit" value="Search">     </center>     </form>     <?     }     else     {    

// form submitted, search     }    

// clean up     mysql_close($connection);      ?>     </body>     </html>

Here’s what the form looks like.

The Perfect Job - Part 2

I’ve implemented two different levels of search here. The first level simply displays all applications for a specific post, as selected from a drop-down list. This comes in very handy when you need to count the number of applications received in response to a particular listing, or aren’t too sure what you’re looking for and just need to eyeball a bunch of resumes.

This list can be further refined by specifying the type of educational qualifications and/or the skills and experience the candidate should have. While the educational qualifications (degrees and subjects) can be selected from a list, the skills may be entered into a free-form text field, separated by whitespace. The administrator also has the option of specifying the level of expertise required, with a set of comparison operators.

Copyright Melonfire, 2000. All rights reserved.

Building Blocks

Once the form has been submitted, a basic query is generated to return a list of applications for the specific job. Then, depending on the criteria selected, that basic query is further modified with AND clauses to refine the list of results.

<?       // search.php - search for specific applications      // includes      // open connection to database      $connection = mysql_connect($hostname, $user, $pass) or die       ("Unable to connect!");      if(!$submit)      {     

// form not yet submitted, display form      }      else      {     

// form submitted, search      // check for missing parameters      if (!$jcode || $jcode == "")      {      header("Location:error.php");      exit;      }     

// set up basic query and joins      $query = "SELECT DISTINCT r_user.rid, r_user.lname,       r_user.fname, r_user.email from r_user, r_skill, r_education       WHERE r_user.jcode = '$jcode'";     

// if skills criteria selected      if(!empty($skills) && !empty($exp_modifier) && !empty($years))      {     

// modify query further      $query .= " AND r_user.rid = r_skill.rid  AND (";     

// tokenize keyword list      $keywords = split(" ", $skills);     

// iterate through list      for ($x=0; $x<sizeof($keywords); $x++)      {      trim($keywords[$x]);     

// this searches for skill1 AND skill2 AND ...      // make this OR if you want an OR-type search      if($x != 0)      {      $query .= " AND";      }       $query .= " (r_skill.skill LIKE '%" . $keywords[$x] ."%' AND       r_skill.experience " .  $exp_modifier . $years . " )";      }      $query .= ")";      }     

// if education criterial selected      if(!empty($degree) && !empty($subject))      {     

// modify query further      $query .= " AND r_user.rid = r_education.rid AND       r_education.fk_degree = '$degree' AND      r_education.fk_subject = '$subject'";      }     

// execute query      $result = mysql_db_query($database, $query, $connection) or die       ("Error in query: $query. " . mysql_error());     

// number of records found      $count = mysql_num_rows($result);     

// uncomment for debug purposes - echo the query      // echo $query . "<p>";      ?>      <html>      <head>      <basefont face="Verdana" size="2">      </head>      <body bgcolor=white>      <? $image="search.jpg"; ?>      <? include("header.inc.php"); ?>      Your search returned <? echo $count; ?> match(es)      <p>      <ul>      <?     

// list matches      while (list($rid, $lname, $fname, $email) = mysql_fetch_row($result))      {      echo "<li><a href=resume_details.php?rid=$rid>$lname,       $fname &lt;$email&gt;</a>";      }      ?>      </ul>      <?      }     

// clean up      mysql_close($connection);       ?>      <? include("footer.inc.php"); ?>      </body>      </html>

Pay special attention to the section which sets up the query for skills. Since the skills field is a whitespace-separated list of values, it’s necessary to first split up the list, and create an SQL clause for each value. The clauses are then joined together with an AND conjunction, to ensure that the resultset includes all the skills specified (you can change this to OR if you’d like any of the skills instead).

The end result of this will be a list of names and email addresses, linked to a script which displays detailed information for that candidate.

Of course, this is only one option for the search engine. There are numerous possible configurations, and you may need to modify this as per your specific requirements.

One of the obvious flaws in this one, for instance, is that it assumes the same level of expertise for every skill selected – there’s no way I can look for candidates with three years experience in Perl and five years experience in C++. In order to accomplish this, I would need to create multiple skill-experience field pairs, and query against each of them.

It should be noted also that there is an alternative approach to this keyword-search technique. Currently, my application form allows applicants to enter skills in whatever format they desire (each skill is a text field, not a list.) If, instead, I had an exhaustive list of skills available, I could have the candidates simply select from a list box, adding an extra level of integrity to the data being collected. This would also make the search process more efficient, by doing away with the wildcards and LIKE clauses in the queries above.

The downside of this approach is that, since you are restricting the candidate to a pre-defined list of job skills, the list must be exhaustive enough to cover all possibilities. Since this seemed difficult, I decided not to adopt this approach, and instead went with the free-form approach… but if it works for you, you might want to consider it.

Copyright Melonfire, 2000. All rights reserved.

The Devil Is In The Details

The "resume_details.php" script represents the end point of the administrator experience. Its purpose is to compile all the information stored about a specific candidate in the various tables into a composite data sheet, and display this in a structured format.

<?        // resume_details.php - build a resume       // includes       include("config.php");        include("functions.php");       

// check for missing parameters       if (!$rid || $rid == "")       {       header("Location:error.php");       exit;       }      

// open connection to database       $connection = mysql_connect($hostname, $user, $pass) or die        ("Unable to connect!");      

// get personal information       $query = "SELECT fname, lname, dob, addr1, addr2, city, state,        zip, country, phone, email, url, relo, posted from r_user,        country WHERE r_user.fk_country = country.id AND rid = '$rid'";       $result = mysql_db_query($database, $query, $connection) or die        ("Error in query: $query. " . mysql_error());      

// error check       if (mysql_num_rows($result) <= 0)       {       header("Location:error.php");       exit;       }       else       {      

// obtain data from resultset       list($fname, $lname, $dob, $addr1, $addr2, $city, $state, $zip,        $country, $phone, $email, $url, $relo, $posted) =        mysql_fetch_row($result);       ?>       <html>       <head>       <basefont face="Verdana" size="2">       </head>       <body bgcolor=white>       <? $image="resume.jpg"; ?>       <? include("header.inc.php"); ?>       <img src="images/pi.gif">       <br>       <b>Name:</b> <? echo $fname . " " . $lname; ?>       <p>       <b>Date of birth:</b> <? echo fixDate($dob); ?>       <p>       <b>Address:</b><br> <? echo "$addr1<br>"; if($addr2)        { echo "$addr2<br>"; }        echo "$city $zip<br>$state, $country"; ?>       <p>       <b>Phone:</b> <? echo $phone; ?>       <p>       <b>Email address: </b><a href="mailto:<? echo $email; ?>">       <? echo $email; ?></a>       <p>       <b>Web site:</b> <? if($url) { echo "<a target=new        href=$url>$url</a>"; }        else { echo "None"; } ?>       <p>       <?      

// get education history       $query = "SELECT institute, degree, subject, year from r_education,        degree, subject WHERE r_education.fk_degree = degree.id AND        r_education.fk_subject = subject.id AND rid = '$rid' ORDER BY year";      

$result = mysql_db_query($database, $query, $connection) or die        ("Error in query: $query. " . mysql_error());       if(mysql_num_rows($result) > 0)       {       echo "<img src=images/ed.gif><br>";       while (list($institute, $degree, $subject, $year ) =        mysql_fetch_row($result))       {       echo "<b>Institute:</b> $institute<br>";       echo "<b>Degree:</b> $degree ($subject, $year)<p>";       }       }       ?>       <?      

// get employment history       $query = "SELECT employer, industry, start_year, end_year,        responsibilities from r_employment, industry WHERE        r_employment.fk_industry = industry.id AND        rid = '$rid' ORDER BY end_year"; $result = mysql_db_query($database,        $query, $connection) or die ("Error in query: $query. " . mysql_error());       if(mysql_num_rows($result) > 0)       {       echo "<img src=images/em.gif><br>";       while (list($employer, $industry, $start_year,        $end_year, $responsibilities) = mysql_fetch_row($result))       {       echo "<b>Employer</b>: $employer ($start_year-$end_year)<br>";       echo "<b>Industry</b>: $industry<br>";       echo "<b>Responsibilities</b>: <br>$responsibilities<p>";       }       }       ?>       <?      

// get skills       $query = "SELECT skill, experience from r_skill WHERE        rid = '$rid' ORDER BY experience";       $result = mysql_db_query($database, $query, $connection) or die        ("Error in query: $query. " . mysql_error());       if(mysql_num_rows($result) > 0)       {       echo "<img src=images/sk.gif><br>";       while (list($skill, $experience) = mysql_fetch_row($result))       {       echo "<b>$skill</b><br>";       echo "$experience years experience<p>";       }       }       ?>       <?      

// get references       $query = "SELECT name, phone, email from r_reference WHERE rid = '$rid'";       $result = mysql_db_query($database, $query, $connection) or die        ("Error in query: $query. " . mysql_error());       if(mysql_num_rows($result) > 0)       {       echo "<img src=images/ref.gif><br>";       while (list($name, $phone, $ref_email) = mysql_fetch_row($result))       {       echo "<b>Name:</b> $name<br>";       echo "<b>Phone:</b> $phone<br>";       if ($ref_email) { echo "<b>Email address:</b>        <a href=mailto:$ref_email>$ref_email</a><p>"; } else { echo "<p>"; }       }       }       mysql_close($connection);       ?>       <img src="images/misc.gif">       <br>       <b>Willing to relocate:</b> <? if($relo == 1) { echo "Yes"; }        else { echo "No"; } ?>       <p>       Resume posted on <b><? echo fixDate($posted); ?></b>       <p>       <a href="javascript:history.back()">Go back to applicant list</a>, or        <a href="search.php">search again</a>       <? include("footer.inc.php"); ?>       </body>       </html>       <?       }       ?>

Nothing too complex here – there are five main sections, and this script queries the corresponding five tables to build a data sheet containing the candidate’s personal information, employment history, educational qualifications, references and skills – in effect, doing the reverse of the "apply_rslt.php" script. This data sheet has all the information an HR manager needs to get in touch with a candidate and begin the recruitment process.

Copyright Melonfire, 2000. All rights reserved.

Handling The Gray Areas

The last script – and the simplest – is the error handler, "error.php". If you look at the source code, you’ll notice many links to this script; very simply, "error.php" intercepts the error and converts it to a human-readable error message, which is then displayed to the user.

<html>        <head>        <basefont face="Verdana" size="2">        </head>        <body bgcolor=white>        <? $image="error.jpg"; ?>        <? include("header.inc.php"); ?>       

There was an error accessing the page you requested. Please         <a href="job_list.php">return to the main page</a> and try again.        <? include("footer.inc.php"); ?>        </body>        </html>

Endgame

And that just about concludes this case study. Throughout this development effort, I have made widespread use of database normalization techniques, PHP’s built-in functions, HTTP headers, and mySQL database queries. If you are new to PHP, I hope that the effort has been instructive, and that it has helped you gain a greater understanding of these powerful open-source tools.

If you’d like to learn more about some of the issues described throughout the course of this article, here are a few links:

Protecting Web pages with HTTP authentication: http://www.apacheweek.com/issues/96-10-18#userauth

mySQL functions available in PHP: http://www.php.net/manual/en/ref.mysql.php

I believe that a tool such as the one described over the preceding pages offers tremendous benefits to any organization in its recruitment efforts. By obtaining and storing information in electronic format, it reduces paperwork; by imposing a structure on user information, it makes it easier and quicker to locate information; and by using a database, it ensures that data does not get corrupted.

It should be noted also that this is an initial release of the application, and I expect it to evolve further, with new features being added and old features being upgraded. It’s always a good idea to review both design and code as the application evolves – I plan to do this a little further down the road, and to make changes to both the database schema and the scripts themselves. This process should take place in conjunction with the development plan for new features, so that the addition of new features does not add to overhead and cause performance degradation.

Until then, though, I’m going to kick back with a cool drink and a good book.

Note: All examples in this article have been tested on Linux/i586 with Apache 1.3.12, mySQL 3.23 and PHP 4.02. Examples are illustrative only, and are not meant for a production environment. YMMV!

Replay

Category: programming Time: 2002-09-04 Views: 3
Tags:

Related post

  • The Perfect Job - Part 1 2002-08-28

    Zen And The Art Of Recruitment It might not seem all that hard, but manning an organization's Human Resources division is actually a pretty difficult task. Sure, HR guys and gals don't have to worry about memory leaks, garbage collection or mangled c

  • The Perfect Desktop - Part 1: Fedora Core 6 2013-09-08

    There is a new revision of this tutorial available for Debian 6 (Squeeze). The Perfect Desktop - Part 1: Fedora Core 6 Version 1.0 Author: Falko Timme With the release of Microsoft's new Windows operating system (Vista), more and more people are look

  • The Perfect Desktop - Part 3: Ubuntu 6.10 Edgy Eft 2014-10-14

    There is a new revision of this tutorial available for Ubuntu 14.10 (Utopic Unicorn). With the release of Microsoft's new Windows operating system (Vista), more and more people are looking for alternatives to Windows for various reasons. This tutoria

  • The Perfect Desktop - Part 2: Mandriva Free 2007 2015-04-16

    There is a new revision of this tutorial available for Mandriva Linux 2010.1 (Spring). The Perfect Desktop - Part 2: Mandriva Free 2007 Version 1.0 Author: Falko Timme With the release of Microsoft's new Windows operating system (Vista), more and mor

  • The perfect miter/join for the pointy part of a speech bubble 2014-09-19

    a young designer working for us made this speech bubble as part of a larger item ... Consider the join or miter of the "pointy part".. I'm thinking it might look poorly-done: it should be a tiny bit smoother (I guess using a spline for that join

  • The Perfect Linux Firewall Part I -- IPCop 2014-12-21

    The Perfect Linux Firewall Part I -- IPCop Version 2.3 Author: Joseph Guarino This document describes how to install the GNU/Linux GPL IPCop firewall and create a small home office network. In the second installment we cover creating a DMZ for hostin

  • The perfect cron job as a wake up service 2010-11-10

    I need a cron job script coded on MAC OS X following the process below: Put the computer into sleep mode on weekdays except Fridays at 10:30 pm. Wake the computer up from sleep, boost the volume to the max, and start playing a mp3 file located in /va

  • The Perfect Server - Mandriva 2008 Free - parts missing 2015-08-14

    Hi! Very nice howto falko but some "mini-part" at part 4 (1 --> 3 http://www.howtoforge.com/perfect_server_mandriva_2008.0_p4) are missing. Can they be brought up again Please Thanks for a great site / Zunk --------------Solutions------------

  • The JSP Files - Parts 1 to 8: Tagged and Bagged 2002-06-06

    Welcome to the JSP Files! If you're interested in learning JSP, you've come to the right place! Over the coming weeks you'll find the following comprehensive tutorials available here - so be sure to check back each week to get the latest installment.

  • The Robot Factory - Part One 2011-10-10

    Adding and Deleting Resources in Sinatra In this tutorial I'm going to go through how to use Sinatra to add and remove resources to and from a database. To demonstrate this, I'm going to build a tiny web app called The Robot Factory that allows users

  • The Perfect Server - Ubuntu Gutsy Gibbon (Ubuntu 7.10) w/ISPConfig 2012-03-09

    Hello HTF group... I am following the HTF Tutorial beyond the part detailing installation of Ubuntu 7.10: http://www.howtoforge.com/perfect_server_ubuntu7.10 Presently I am having trouble when Sending OR Receiving Email from this server. I receive th

  • Companion Script #2 for The Perfect Server - Fedora 13 x86_64 [ISPConfig 3]" 2012-05-08

    Script Name: PerfectServer.2.sh #!/bin/bash clear # ==================================================================== echo "The Perfect Server - Fedora 13 x86_64 [ISPConfig3]" echo "Script=PerfectServer.2.sh" echo "http://www.h

  • The Perfect Setup - Debian Etch: smart_host 2012-11-11

    On Fedora Core 6 in /etc/mail/sendmail.mc I configured Sendmail's smart_host, so visitors of my site practically use my ISP's smtp server to send me their message filling in a web form. For configuration I used instructions provided by: http://www.go

  • The Perfect SpamSnake - Ubuntu Jeos 10.10 Maverick Meerkat - transportmaps 2013-06-16

    Please help again. this setup is proving to be more challenging as its not too clear following the steps. Heres my setup . I want the spam snake to scan and relay to an exchange server . Emails however are getting queued on the local server ( spam sn

  • In search of the perfect howto 2013-12-08

    Gentlemen, Please allow me first to spend a little time in venting my spleen. I am sick to the back teeth with all these howto's not only here but throughout 90% of the Linux and Unix internet world on how to do this and how to do that. I'm sick to t

  • The Perfect Server - CentOS 5.3 - liblzo.so.1 2015-09-04

    After installing CentOS 5.3 by "the perfect server" tutorial, when i run "yum update" it says: Missing Dependency: liblzo.so.1()(64bit) is needed by package lzop-1.01-2.el5.rf.x86_64 (installed) Error: Missing Dependency: liblzo.so.1()

  • 3 Pro Tips For Finding the Perfect Image 2015-11-11

    We Held a Webinar! You may have heard that we have partnered up with Graphic Stock recently to bring your a chance to win $5,000. You may have also seen that last week we held a webinar with our very own Design & UX channel editor Alex Walker. It was

  • Sabotage! Coping With The Joe Job 2004-02-04

    If you run an ecommerce Website, you probably find that competition can be very steep, especially in certain markets. Maintaining a credible reputation in world full of fly-by-night scams, and earning the trust of your visitors, can be among the most

  • Not the Perfect Time Tracking Tool 2006-11-13

    The last post received some very interesting comments, and even a few mentions of specific time tracking systems that our readers use. As a process and methodology fanatic, I'm always interested in any tools that can help me to be more efficient – es

iOS development

Android development

Python development

JAVA development

Development language

PHP development

Ruby development

search

Front-end development

Database

development tools

Open Platform

Javascript development

.NET development

cloud computing

server

Copyright (C) avrocks.com, All Rights Reserved.

processed in 2.414 (s). 13 q(s)