CSI: PHP

"Looking at your tweets I cannot even fathom what your job is. CSI:PHP?" — @grmpyprogrammer

Words Escape Me

| Comments

Look, I know this is going to be tough to read, and I usually try to post short, snappy code snippets, but this is just too good. Or sad. Whatever. Words truly escape me.

Take it away anonymous submitter:

“Look at all these standalone ternaries for validating form input. What a mess! They’re embedded in what would normally be controller logic. These should be if() statements or, preferably, a separate validating class.”

Indeed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php

(!is_numeric($input['raw_gpa']) || $input['raw_gpa'] < 0 || $input['raw_gpa'] > 4) ? ($errors[] = "Your unweighted GPA must be between 0 and 4. You must indicate your unweighted GPA, and this must be between 0 and 4.") : ('');
($input['gpa_max'] < 0 || $input['gpa_max'] > 200) ? ($errors[] = "Your school's max possible GPA must be between 0 and 100.") : ('');
($input['gpa'] < 0 || $input['gpa'] > $input['gpa_max']) ? ($errors[] = "Your weighted GPA must be between 0 and your school's max weighted GPA.") : ('');

(($input['act'] == "") && (($input['sat_verb'] == "") || ($input['sat_math'] == ""))) ? ($errors[] = "To use this site, you must indicate your SAT scores, or your ACT scores, or both.") : ('');

(!is_numeric($input['act']) && ($input['act'] != "")) ? ($errors[] = "Your ACT score must be a numeric value, or blank.") : ('');
(!is_numeric($input['act_eng']) && (!empty($input['act_eng']))) ? ($errors[] = "Your ACT English score must be a numeric value, or blank.") : ('');
(!is_numeric($input['act_math']) && (!empty($input['act_math']))) ? ($errors[] = "Your ACT Math score must be a numeric value, or blank.") : ('');
(!is_numeric($input['act_read']) && (!empty($input['act_read']))) ? ($errors[] = "Your ACT Reading score must be a numeric value, or blank.") : ('');
(!is_numeric($input['act_sci']) && (!empty($input['act_sci']))) ? ($errors[] = "Your ACT Science score must be a numeric value, or blank.") : ('');

(!is_numeric($input['sat_math']) && ($input['sat_math'] != "")) ? ($errors[] = "Your SAT math must be a numeric value, or blank.") : ('');
(!is_numeric($input['sat_verb']) && ($input['sat_verb'] != "")) ? ($errors[] = "Your SAT verbal must be a numeric value, or blank.") : ('');
(!is_numeric($input['sat_writ']) && ($input['sat_writ'] != "")) ? ($errors[] = "Your SAT writing must be a numeric value, or blank.") : ('');

((($input['act'] > 36) || ($input['act'] < 1)) && ($input['act'] != "")) ? ($errors[] = "Your ACT score is out of the valid range.") : ('');
((($input['act_eng'] > 36) || ($input['act_eng'] < 1)) && ($input['act_eng'] != "")) ? ($errors[] = "Your ACT English score is out of the valid range.") : ('');
((($input['act_math'] > 36) || ($input['act_math'] < 1)) && ($input['act_math'] != "")) ? ($errors[] = "Your ACT Math score is out of the valid range.") : ('');
((($input['act_read'] > 36) || ($input['act_read'] < 1)) && ($input['act_read'] != "")) ? ($errors[] = "Your ACT Reading score is out of the valid range.") : ('');
((($input['act_sci'] > 36) || ($input['act_sci'] < 1)) && ($input['act_sci'] != "")) ? ($errors[] = "Your ACT Science score is out of the valid range.") : ('');
((($input['sat_math'] > 800) || ($input['sat_math'] < 200)) && ($input['sat_math'] != "")) ? ($errors[] = "Your SAT math score is out of the valid range.") : ('');
((($input['sat_verb'] > 800) || ($input['sat_verb'] < 200)) && ($input['sat_verb'] != "")) ? ($errors[] = "Your SAT verbal score is out of the valid range.") : ('');
((($input['sat_writ'] > 800) || ($input['sat_writ'] < 200)) && ($input['sat_writ'] != "")) ? ($errors[] = "Your SAT writing score is out of the valid range.") : ('');

((($input['psat'] > 240) || ($input['psat'] < 60)) && ($input['psat'] != "")) ? ($errors[] = "Your PSAT is out of the valid range.") : ('');

(!array_key_exists($input['nat_merit'], $nationalMeritArray)) ? ($errors[] = "Please indicate whether or not you were awarded National Merit or National Achievement awards.") : ('');
(!array_key_exists($input['ap'], $apCountArray)) ? ($errors[] = "Please estimate how many APs your school offers.") : ('');

(!array_key_exists($input['hs_type'], $hs_type_array)) ? ($errors[] = "Please indicate what type of high school you attend (public, private, magnet, etc.).") : ('');
(!array_key_exists($input['hs_state'], $state_array)) ? ($errors[] = "Please indicate the state that your high school is in.") : ('');
($input['hs_city'] == "") ? ($errors[] = "Please indicate the city that your high school is in.") : ('');

(array_search($input['decile'], $decile_array) === false) ? ($errors[] = "Please indicate your class rank.") : ('');

((!is_numeric($input['class_size']) || $input['class_size'] < 1 || $input['class_size'] > 10000) && $input['class_size'] != "") ? ($errors[] = "If you indicate your class size, it must be numeric (without words, periods, or commas).") : ('');

Too Few DEFINEs for My Taste

| Comments

The Crime

It takes a big man to admit when he’s wrong, and @dilbert4life is one of those men. Here’s a snippet of horror that he wrote around a year-and-a-half ago.

Too many defines? Nay! I say let the site grow and see just how many we can stuff in there.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
$slug = str_replace('.php', '', $_SERVER['REQUEST_URI']);
$slug = preg_replace('/\//', '', $slug, 1);
$slug = explode('?', $slug);
$slug = $slug[0];
if($slug == 'index' || $slug == '') {
    $slug = "/";
    define(IS_HOME, true);
    define(IS_ADMIN, false);
    define(IS_NEWS, false);
    define(IS_CONTACT, false);
} elseif(preg_match('/admin/', $slug)) {
    define(IS_HOME, false);
    define(IS_ADMIN, true);
    define(IS_NEWS, false);
    define(IS_CONTACT, false);
} elseif(preg_match('/news/', $slug)) {
    define(IS_HOME, false);
    define(IS_ADMIN, false);
    define(IS_NEWS, true);
    define(IS_CONTACT, false);
} elseif(preg_match('/contact/', $slug)) {
    define(IS_HOME, false);
    define(IS_ADMIN, false);
    define(IS_NEWS, false);
    define(IS_CONTACT, true);
} else {
    define(IS_HOME, false);
    define(IS_ADMIN, false);
    define(IS_NEWS, false);
    define(IS_CONTACT, false);
}

Rehabilitation

Normally, a submitter, whether anonymous or not, will simply send in an incident report and leave it at that. @dilbert4life has gone above and beyond, however. Not only did he submit his crime, but he submitted evidence of his rehabilitation.

1
2
3
4
5
6
7
8
<?php
$uri = parse_url($_SERVER['REQUEST_URI']);
$path = explode('/', $uri['path']);

define('IS_HOME', (empty($path[1])));
define('IS_ADMIN', ($path[1] === 'admin'));
define('IS_NEWS', ($path[1] === 'news'));
define('IS_CONTACT', ($path[1] === 'contact'));

I especially like how he replaced three lines of garbage with parse_url.

What Idiot Wrote This? Oh, Wait, It Was Me.

| Comments

Starting with this post, we have a new category here at CSI: PHP. It’s called ‘mea culpa’, and it’s criminal code written by yours truly.

Behold the awesome that is error(), an unholy concoction of PHP, JavaScript, and HTML. It’s the only function in a file called common.php, which makes perfect sense because shut up. Yes, this was in production use, and would dislpay a JavaScript alert with an error message whenever I remembered to use it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php // common.php

function error($msg) {
    ?>
    <html>
    <head>
    <script language="JavaScript">
    <!--
        alert("<?=$msg?>");
        history.back();
    //-->
    </script>
    </head>
    <body>
    </body>
    </html>
    <?
    exit;
}

Stop Rolling Your Own

| Comments

Seriously. Stop it. Or you’ll end up with garbage like this, in which a developer writes two separate functions for converting JSON to an array, only one of which is compatible with json_decode. Yes, both are in production.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php

function jsonToArray($jsonData)
{

    $newArray = array();

    // remove first and last []
    $length = strlen($jsonData) - 2;
    $jsonString = substr($jsonData, 1, $length);

    if ($jsonString != "") {
        // tokenize, using , as a divider
        $newArray = explode(",", $jsonString);
    }
    return $newArray;
}

// Converts JSON data string to PHP array
// Assumes this format: ["Some text","Even more text"]
function jsonStringsToArray($jsonData)
{

    // remove first and last []
    $length = strlen($jsonData) - 2;
    $jsonString = substr($jsonData, 1, $length);

    // tokenize, using , as a divider
    $newArray = explode(",", $jsonString);

    $lastArray = array();

    for ($i = 0; $i < sizeof($newArray); $i++) {

        $thisLength = strlen($newArray[$i]) - 2;
        $lastArray[] = substr($newArray[$i], 1, $thisLength);
    }
    return $lastArray;
}

We Don’t Need No Stinkin’ POST Variables

| Comments

CSI: PHP investigator Duane Gran sent in this horrifying snippet. He explains:

I wondered why dumping the $_POST variables before this section didn’t help in debugging. This occurs in a second step of a 3-step form on a GET request. It applies a set of session fields to the $_POST variable for later use.

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

foreach($_SESSION["purchase"] as $key => $value)
{
    switch($key)
    {  
        case "process_purchase":
            break;
        default:
            $_POST[$key] = $value;
            break;
    }
}

I Do Not Think DRY Means What You Think It Means

| Comments

Perhaps this developer decided it would be better to create convenience methods than to litter their codebase with date format strings. Nothing wrong with trying to DRY up your code, but creating 13 inscrutably named date formatting functions ain’t the way to do it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?php

function formatDate1($date)
{
    return date('n-j-y', $date);
}

function formatDate2($date)
{
    return date('n/j/Y', $date);
}

function formatDate2a($date)
{
    return date('n/j/Y g:ia', $date);
}

function formatDate2b($date)
{
    return date('n.j.Y g:ia', $date);
}

function formatDate3($date)
{
    return date('n/j/y', $date);
}

function formatDate11($date)
{
    return date('n/j', $date);
}

function formatDate4($date)
{
    return date('F j, Y', $date);
}

function formatDate5($date)
{
    return date('F j, Y  g:i:s A', $date);
}

function formatDate6($date)
{
    return date('j-M', $date);
}

function formatDate8($date)
{
    return date('F j, Y  g:i A', $date);
}

function formatDate9($date)
{
    return date('n.j.Y', $date);
}

function formatDate10($date)
{
    return date('M Y', $date);
}

function formatDate12($date)
{
    return date('m/d/Y', $date);
}

I was able to confirm, thanks to further research by today’s anonymous submitter, that at least half of these functions are currently in use.

[EDIT: The wikipedia link wasn’t encoded properly when I posted this. Fixed! Thanks to @papayasoft for pointing it out.]

Concatenation Is Not a Parser Error

| Comments

CSI: PHP isn’t big on the perp walk, but if your crime is (1) public and (2) licensed with an Attribution-NonCommercial-ShareAlike Creative Commons license, then you kinda perp walked yourself.

1
2
3
4
5
6
7
8
9
<?php

// What will this print out in php5?
$earth = 'World';
$string1 = "Hello " .
$string2 = $earth . '!';
$string = $string1 . $string2;

echo $string;

The author posits the output, Hello World!World!, is a possible parser error or internal assignment nonsense. What Hello World!World! actually represents is PHP string handling and variable assignment 101.

I will concede that determining the output of $string is something of a light brain teaser. However, if you’re confused by concatenation and variable assignment to the point that you write a blog post about it and present it as a parser error, I can only hope and pray you’re trolling.

Exit question, “If a plane crashes on the border of Canada and the United States, where do you bury the survivors?”

Encrypt Passwords for Highest Level of Security

| Comments

Thanks to Justin Carmony for this awesome slice of fail.

1
2
3
4
5
6
7
8
9
10
11
12
<?php

class SecurityFail
{

    // Encrypt Passwords for Highest Level of Security.
    static public function encrypt($pword)
    {
        return md5($pword);
    }

}

There are right ways and wrong ways to encrypt and store passwords, and a simple md5() hash is one of the wrong ways. Here are some links you might research instead of rolling your own crypto.

The Interview

| Comments

Yes, this really happened.

Q: How long have you been working with PHP?

A: About 8 years.

Q: On a scale of 1 – 10, how would you rate your proficiency with PHP?

A: I’d say I’m an expert.

Q: Can you tell me the difference between an abstract class and an interface, and when you might use either?

A: Is that a Java question?

For Your Consideration

| Comments

This was sent along anonymously, along with the question:

“Does this count as horror code or pure evil genius code?”

What say you, dear reader? I cut and paste, you decide.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

function cli_parsestr($string, $config, $mainconf, $options, $custom = array())
{
    if (empty($string)) {
        return '';
    }

    $replaces = array(
            'config' => '/%%$0%%/',
            'mainconf' => '/%\*$0\*%/',
            'options' => '/%&$0&%/',
            'custom' => '/%\\\$$0\\\$%/',
            );

    foreach ($replaces as $var => $replace) {
        if (!empty($$var) && is_array($$var)) {
            $string = preg_replace(preg_replace('/.+/', $replace, array_keys($$var)), array_values($$var), $string);
        }
    }
    return $string;
}