Skip to content

Latest commit

 

History

History
13190 lines (7098 loc) · 458 KB

The Zend Certification.md

File metadata and controls

13190 lines (7098 loc) · 458 KB

Control Structures

Control structures allow you to analyze variables and then choose a direction for your program to flow in. In this section, we’re going to be looking at several different sorts of control structures and how they’re implemented in PHP.

Conditional Structures

PHP supports if, else, elseif, switch, and ternary conditional structures.

​If structures look like this:

'one', 'b' => 'two', 'c' => 'three' ]; foreach ($arr as $value) { echo $value; // one, two, three } foreach ($arr as $key => $value) { echo $key; // a, b, c echo $value; // one, two, three } ### Breaking Out of Loops There are two ways to stop an iteration of a loop in PHP— break and continue. Using continue has the effect of stopping the current iteration and allowing the loop to process the next evaluation condition. This allows you to let any further iterations to occur. Using break has the effect of stopping the entire loop and no further iterations will occur. The break statement takes an optional integer value that can be used to break out of multiple levels of a nested loop. If no value is specified, it defaults to 1. ### Namespaces Namespaces help you avoid naming collisions between libraries or other shared code. A namespace will encapsulate the items inside it so that they don’t conflict with items declared elsewhere. They can be used to avoid overly descriptive names for classes, to sub-divide a library into sections, or to limit the applicability of constants to one section of code. Classes encapsulate code into instantiable units. Namespaces group functions, classes, and constants into spaces where their name is unique. The namespace declaration must occur straight after the opening 'Bob', 'age' => 23 ]; xdebug_debug_zval( 'arr' ); The output from this script looks like this: arr: (refcount=1, is_ref=0)=array ( ​'name' => (refcount=1, is_ref=0)='Bob', ​'age' => (refcount=1, is_ref=0)=23) We can see that three zval containers are created, one for the array variable itself and one for each of its two values. Just as for scalar variables, if we had a third member of the array with the same value as another member then instead of creating a new zval container PHP will increase the refcount and point the duplicate symbol to the same zval. ### Memory Leaks in Arrays and Objects Memory leaks can occur when a composite object includes a reference to itself as a member. This is more likely to occur in use-cases with objectsbecause PHP always assigns objects by reference. Possibly, for example, in parent-child relationships such as might be found in an ORM model. The PHP Manual has a series of diagrams explaining this on the refcounting basics page.[19](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-534) The problem occurs when you unset a composite object that has a reference to itself. In this event, the symbol table is cleared of a reference to the zval structure that was used to contain the variable. PHP does not iterate through the composite object because this would result in recursion asit follows links to itself. This means that the member in the variable that is a reference to itself is not unset, and the zval container is not marked as free. There is no symbol pointing to this zval container and so the user cannot free the memory herself. PHP will clear up these references at the end of the request. Remember that PHP is not intended to be a long-running language and is designed to be a text processor built for serving specific requests within the context of a web application. ### Garbage Collection The garbage collector clears circular references, which are those where a complex object contains a member that refers to itself. PHP will initiate garbage collection when the root buffer is full or when the function gc_collect_cycles() is called. The garbage collector will only cause a slowdown when it actually needs to do something. In smaller scripts where there is no leakage it won’t cause a performance drop. Garbage collection is likely to be of benefit in long-running scripts or those where a memory leak is repeatedly created, such as processing a very large amount of database records using ORM models that leak. ### The Opcode Cache PHP iscompiled into a sequence of intermediate instructions that are executed in order by the runtime engine. These instructions are called opcodes or bytecodes and this process occurs every time the script is run. The bytecode is interpreted by the runtime engine; therefore, PHP is both precompiled and interpreted. An opcode cache stores the converted instructions for a script. Subsequent calls to the script do not require the script to be interpreted prior to being run. In 2013, Zend contributed their optimization engine to PHP. Known as opcache, it is baked into distributions of PHP as of version 5.5 and is probably the most commonly used PHP opcode cache. Note Opcache is built into PHP 7.1 and is enabled by default in your php.ini [20](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-535) settings. Take note of the setting opcache.revalidate_freq. This determines the interval in seconds that PHP will scan for changesin the source file before recompiling it. You can set it to 0 to tell PHP to always scan for changes. PHP will not scan the file more than once per request. In addition to the cache built into PHP, there are a number of third-party opcode caches available (see Wikipedia[21](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-536) if you’re interested). Tip Using the opcode cache results in significant performance increases. ### Extensions PHP extensions extend on the functionality offered by the core language. A number of them are enabled by default into standard repository distributions of PHP. Other extensions need to be downloaded and installed manually. PECL is a repository for PHP extensions. It provides an easy way to download and install extensions on Linux. Windows machines need to compile and install extensions manually, but usually they’re distributed in a compiled form and you just need to edit your INI file to enable them. PHP includes several extensions that cannot be removed from PHP with compilation flags. These extensions include core functionality such asreflection, arrays, date and time, SPL, and math. You should be able to rely on them being installed. #### Installing an Extension Extensions are enabled through the php.ini file using the “extension” setting to specify the filename of the extension, like this for mcrypt: extension=mcrypt.so; You can set the extension directory with a setting in your php.ini file like so: extension_dir = "/usr/lib/php5/20121212/mcrypt.so" Different systems may provide convenient ways of installing and enabling extensions. PECL extensions can be installed using the pecl command-line utility. #### Checking for Installed Extensions The extensions installed will display if you call phpinfo() or if you use the more specific command get_loaded_extensions(). Running php –m from the shell will show a list of extensions installed. You can check if an extension is loaded by calling extension_loaded(). This is recommended if you’re using a function in an extension that isnot loaded by default. Here is an example from the PHP Manual: getMessage(); } | Exception caught in A | | ------------------------------------------------------------ | | Error caught in global scope: Call to undefined function C() | | Error caught in global scope: Call to undefined function b() | | None of the above | Q5: What will this script output? getMessage(); } | Exception caught in A | | ------------------------------------------------------------ | | Error caught in global scope: Call to undefined function C() | | 1| | Error caught in global scope: Call to undefined function b() | | None of the above | Q6: What will this script output? "bananas"; $b = $a ?? $c ?? 10; echo $b; | -1 | | ------ | | 0| | 1| | 10 | | apples | Q9: What is the output of this script? 10 << 1; | -1 | | ---- | | 0| | 1| | 10 | Q10: What is the output of this script? $value) { ​echo "$arg is $value" . PHP_EOL; } } myFunc('variable', 3, 'parameters'); /* 0 is variable 1 is 3 2 is parameters */ The following code illustrates an obscure difference between PHP 7 and PHP 5: nature . ' ' . $boundVariable; ​}; } } class Cat extends Animal { protected $nature = 'Awesome'; } class Dog extends Animal { protected $nature = 'Friendly'; } $cat = new Cat; $closure = $cat->getClosure(); echo $closure(); // Awesome Animal $closure = $closure->bindTo(new Dog); echo $closure(); // Friendly Animal There are two important things to notice in this code. First, binding the closure to a different object returns a duplicate of the original, so you have to assign the result of calling bindTo() to a variable. Second, the new closure will have the same bound variables and body, but a different bound object and scope. In the previous example, the $boundVariable is duplicated into the new closure when we bind to the new object. ### Self-Executing Closures You can create self-executing anonymous functions in PHP 7 using syntax very similar to JavaScript: favorite = "Cheeseburger"; echo "$dogfood[0]"; // Pellets echo "$catfood->favorite"; // Cheeseburger PHP allows the use of curly braces for you to explicitly tell the parser that part of a string must be evaluated. This is necessary, for example, when outputting an element from an array where it might not be immediately clear that the square brackets are intended as punctuation in the string or as syntax to reference an element in the array. Let’s look at some examples of its usage: name = "Cheeseburgers"; $cat = new stdClass(); $cat->canhaz = [$catfood]; echo "$cat->canhaz[0]->name";// array to string conversion echo "{$cat->canhaz[0]->name}"; // Cheeseburgers ### Control Characters When PHP encounters a complex string, one that it declared in double quotes, it will evaluate it for variables and control characters. The control characters are marked by a backslash followed by the code. Using a backslash followed by anything other than a control character will result in the backslash being displayed. "\u{1F44B}", ​'latinchars' => "Hello", ​'accentedChars' => "ça va?" ]; foreach ($waysToSayHello as $method => $string) { echo "$method : encoding [" . mb_detect_encoding($string, 'ISO-8859-1') . '] ' . ​'encoding [' . mb_detect_encoding($string, ['ASCII','UTF-8']) . '] ' . ​'strlen [' . strlen($string) . '] ' . ​'mb_strlen [' . mb_strlen($string) . '] ' . ​'first character[' . $string[0] . ']'; echo "\r\n"; } /* ​emoji : encoding [ISO-8859-1] encoding [UTF-8] strlen [4] mb_strlen [1] first character[![A456636_1_En_3_Figb_HTML.gif](file:///home/antonio/Escritorio/PHP%207%20Zend%20Certification%20Study%20Guide%20-%20Andrew%20Beak.htmlz_FILES/images/000002.gif)] ​latinchars : encoding [ISO-8859-1] encoding [ASCII] strlen [5] mb_strlen [5] first character[H] ​accentedChars : encoding [ISO-8859-1] encoding [UTF-8] strlen [7] mb_strlen [6] first character[![A456636_1_En_3_Figc_HTML.gif](file:///home/antonio/Escritorio/PHP%207%20Zend%20Certification%20Study%20Guide%20-%20Andrew%20Beak.htmlz_FILES/images/000007.gif)] ​*/ Remember that PHP doesn’t store encoding information in the string so it can only guess at how the string is encoded. The mb_detect_encoding function will examine the string and try to determine what it is. It does so by comparing the string to a list of encoding schemes and selecting the first scheme under which the string is validly encoded. You can specify encodings (in order) for PHP to try or rely on the default encoding. This explains why the output from mb_detect_encoding is different for the same string—we’re giving PHP different hints about what it could be. Notice that the output from strlen() function differs from mb_strlen. The PHP function strlen returns how many bytes are in the string, not how many characters. Lastly, notice that if we use the array notation method to access a position in the string, we only get a meaningful result if the string is encoded in single byte format. ### Matching Strings Comparing strings in PHP should be done with an appropriate level of care when you’re trying to match different variable types. In chapter [1](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-137), the section on “Casting Variables,” we examined the manual pagesrelating to casting. Make sure that you’re familiar with how PHP castsvarious variable types to string. Using comparison operators like > and < might not always work as expected. It’s common to expect that PHP would use alphabetical order to evaluate strings against these operators. Instead of using alphabetical sorting, PHP uses the ASCII value of the character to make the comparison. Lowercase letters have a higher ASCII value than capitals, so you can have the situation where lowercase letters are placed after capitals, like this: $b) { echo "$a > $b"; } else { echo "$a < $b"; } // developer comes before PHP in the alphabet // but this script outputs // PHP < developer Recall the rules for converting strings to integers discussed in the section on “Casting Variables”. In the following example, the string is cast to an integer value of 12, which equals the float value of 12.00 and so the message is echoed. 0 if str1 is greater than str2, and 0 if they are equal. Tip Remember the spaceship operator? The operator can be used on any variable types, but strcmp is exclusively for strings. There is also a case-insensitive version named strcasecmp() that first converts strings to lowercase and then compares them. This example shows the difference: html text"; $pattern = "/<.*>/"; $matches = []; preg_match($pattern, $subject, $matches); var_dump($matches[0]); // string(21) "html" This outputs string(21) "html", which is clearly more than the HTML tag you were wanting. It is greed that is to blame for this; the * quantifier is greedy and attempts to find the longest possible match. It returns the characters between the opening < of the strong tag and the last > of the closing tag, which is the longest possible match. By contrast, a lazy search returns the shortest possible match. You can modify a quantifier to make it lazy by adding a question mark (?) to it. html text"; $pattern = "/<.*?>/"; // note the pattern has changed

$matches = [];

preg_match($pattern, $subject, $matches);

var_dump($matches[0]); // string(8) ""

There are a lot more options to modify quantifiers, but they are outside of the scope of this book.

Getting All Matches

So far your expressions are returning just the first occurrence of the matching portion of a search string. Let’s say that you want to find all of the matches in the string.

PCRE has a global modifier (more on those later), but PHP uses a separate function called preg_match_all() to return all matches.

html
text"; $pattern = "/<.*?>/";

$matches = [];

preg_match_all($pattern, $subject, $matches);

var_dump($matches);

/*

array(1) {

​ [0] =>

​ array(2) {

​ [0] => string(8) ""

​ [1] => string(9) ""

​ }

​}

*/

Naming Groups

You can name capturing groups by adding ? to the beginning of the bracket that opens the group. For example:

\w+)@(?\w+).(?\w+)/"; $matches = []; if (preg_match($pattern, $subject, $matches)) { var_dump($matches); } In this example, we’re naming the first part of the matching pattern as username, the next as domain, and the next as tld. This is a somewhat naïve example because it won’t work for e-mail addresses like [email protected], but it does serve to show the syntax. The previous example outputs this: array(7) { ​ [0] => string(16) "[email protected]" ​ 'username' => string(4) "test" ​ [1] => string(4) "test" ​ 'domain' => string(7) "example" ​ [2] => string(7) "example" ​ 'tld' => string(3) "com" ​ [3] => string(3) "com" } So you are able to reference $matches['username'] and receive "test" in response, which is convenient. ### Pattern Modifiers You can add a modifier after the closing delimiter of an expression. The following table lists the modifiers. | Modifier | Function | | -------- | ------------------------------------------------------------ | | i | The expression is case-insensitive.| | m | Multiline mode. Strings can span multiple lines and newline characters are ignored. Instead of matching the beginning and end of the string, the ^ and $ symbols will match the beginning and end of the line. | | s| The . meta-character will also match newlines. | | x | Ignore whitespace unless you escape it.| | e | This causes PHP code to be evaluated and is highly discouraged. It isdeprecated as of PHP 5.5 and in PHP 7 will generate a warning, as it isno longer supported. | | U | This makes the quantifiers lazy by default and using the ? after them instead marks them as greedy. | | u | This tells PHP to treat the pattern and string as being UTF-8 encoded. This means that characters instead of bytes are matched. | Chapter [3](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-134) Quiz Q1: You cannot compare a string variable to an integer variable using the greater than or less than operators. You can only compare string and integer values with the equivalence operator. | True | | ----- | | False | Q2: You can use the ________ function to make binary safe case-insensitive comparisons between strings. | <=> | | ---------- | | strcmp | | strcasecmp | | stricmp| Q3: PHP functions that search strings ALWAYS have the parameters in which order. | $haystack, $needle | | -------------------------- | | $needle, $haystack | | It depends on the function | Q4: What does the strspn($subject, $mask) function do? | Searches a string $subject for a substring $mask | | ------------------------------------------------------------ | | Returns the maximum length of a string in $subject that contains only letters contained in $mask | | Returns the minimum length of a string in $subject that contains all of the letters contained in $mask | | It’s a binary-safe way to splice a string specified by $mask out of the $subject string | Q5: What does the strstr($haystack, $needle) function do? | It’s a faster alternative to strpos()| | ------------------------------------------------------------ | | It’s a binary safe alternative to strpos() | | It returns the portion of the $haystack that occurs after the first instance of $needle | | It returns the position in the $haystack where the string $needle first occurs | Q6: What is the output of this code? 10, 1 => 'abc', 2 => 30 ); // associative $arr = array('name' => 'foo', 'age' => 20); // short syntax $arr = ['name' => 'foo', 'age' => 20]; If you do not specify a key then PHP will assign an auto-incrementing numeric key. In the example, the first two assignments are identical because PHP automatically assigns the key. A key may be numeric or a string. An array may contain a mixture of numeric and string keys. Arrays keyed on numbers are called enumerative . The first two examples are enumerative. Arrays that have strings for keys are called associative arrays. The last two examples are associative arrays. There are two syntax forms to declare an array; choosing one is a question of coding style. 'foo', 'age' => 20]; echo $arr['age']; // 20 If you do not specify a key in the brackets, PHP assumes that you are trying to reference a new element. You can use this to add an element to the end of an array: 'id', 'name' => 'foo', 'age' => 20]; $arr[] = 'example'; print_r($arr); This will output the following: Array ( [0] => id [name] => foo [age] => 20 [1] => example ) Note that PHP chose the key by incrementing the highest numeric key in the array. ## Functions That Create an Array There are lots of PHP functions that return an array, but I'm going to introduce a few that are directly related to arrays. The function explode() is used to split up a string into an array. It's easiest to explain by example: 1 [1] => abc [2] => 2 [3] => def ) The implode() function [2](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-50) operates in the reverse manner. It joins the elements of an array together into a string delimited by a string you supply. ​ preg_split() is another function that splits a string into an array. It is similar to explode(), but it uses a regular expression to delimit the field instead of using a literal string. It is documented in the PHP Manual.[3](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-51) You can use the str_split() function [4](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-52) to break a string into an array of chunks. It takes two parameters: the string you want to split, and the length of the chunk to use for each element of the array. 123 [1] => 456 [2] => 78 ) Notice that the string is not evenly divisible by the chunk size and so the final element is only two characters long. If the chunk size is greater than the length of the string, the entire string is returned as the only element of the array. The function returns FALSE if you try to use a negative chunk length. ## Array Operators PHP arrays can be tested for equivalence and identity. We saw in the section on comparison operators that arrays are equivalent if they have the same key and value pairs. They are identical if they have the same key and value pairs, are in the same order, and the key-value are of the same type. The + operator will produce the union of two arrays. When using the + union operator, PHP appends the array on the right of the operator to the left. If a key exists in both arrays, then the left array value isused for the key. 'hello', 'b' => 'world']; $b = ['a' => 'goodbye', 'c' => 'cruel']; echo implode(' ', $a + $b); // hello world cruel In the previous example, both arrays have the key a. The union of the arrays will therefore have the value from $a for this key, because $a was on the left of the union operator. | Example | Name | Result | | --------- | ------------ | ------------------------------------------------------------ | | $a + $b | Union | $b is appended to $a. If a key exists in both arrays, then the value from $a is placed into the union. | | $a == $b | Equality | TRUE if $a and $b have the same key-value pairs| | $a === $b | Identity | TRUE if $a and $b have the same key-value pairs, of the same types, and in the same order. | | $a != $b | Inequality | TRUE if $a is not equal to $b. | | $a <> $b | Inequality | TRUE if $a is not equal to $b. | | $a !== $b | Non-identity | TRUE if $a is not identical to $b. | Let's run through a quick example: 1, 0 => 'a', 1 => 'b']; var_dump($a == $b); // true var_dump($a === $b); // false var_dump($a == $c); // false var_dump($a == $d); // true var_dump($a === $d); // false We can see that $a is equal to $b because the key-value pairs are the same. They are not equivalent, however, because the type of the third element is a string in $a and an integer in $b. ​ $a and $c are not equal even though they have the same values. Arrays are considered equal if they have the same key-value pairs. In this case, we didn't specify a key so PHP assigned an auto-incrementing key for each value. Therefore, they key-value pairs don't match, even though the values are the same. ​ $a and $d are equal because the key-value pairs are the same, but are not identical because they are not in the same order. ## Proper ties of PHP Array Keys PHP arrays are zero-based. PHP array keys are case sensitive: $arr['A'] and $arr['a'] are different elements. Keys may only be a string or an integer. Other variable types are cast into one of these types before being stored. Strings containing decimal valid integers will be cast to the integer type. "hello", 0x03 =>"world", 0b100 => ' this is ', "04" =>"PHP", 8.7 =>"!!!!" ]; var_dump($a); /* array(5) { [2]=> string(5) "hello" [3]=> string(5) "world" [4]=> string(9) " this is " ["04"]=> string(3) "PHP" [8]=> string(4) "!!!!" } */ In the preceding example, we see that the string "2" is converted to integer 2. The hexadecimal and binary formats are both converted to decimal. The string "04" is not converted to an integer because it contains an octal representation and not a decimal. PHP rounds floats toward zero when it casts floats to integers. Another way of putting this is to say that the fractional portion of the number istruncated. For example, the float 133.7 will cast to the integer value 133 (and not rounded up to 134). Booleans can also be cast to integers. The Boolean value true evaluates to integer 1 and false becomes integer 0. Null is treated as an empty string. So the null key will be stored under the key ''. Composite variables (objects and arrays) and resources cannot be used as key. If you try to do so, PHP will issue a warning "illegal offset type". Keys are unique; if multiple elements in an array use the same key (after it has been converted as above), then PHP will use the last one for the value and overwrite all the preceding values. Tip This is a good time to review your type juggling! ### Filling Up Arrays You can use the range() function to add values to an array based on a range of values you specify. You specify the beginning, end, and step size for the range. The PHP Manual has many useful examples, but here is one based on one of the comments: 1 [3] => 2 [5] => 3 [7] => 4 [9] => 5 ) */ Another command called array_fill() will let you fill up an array with a single value. It takes parametersfor the starting index, how many values to fill, and the value to insert. five [11] => five [12] => five [13] => five [14] => five ) Related to this is the function array_fill_keys(). This function will fill up an array with a specific value and lets you specify what keys to use. PHP [3] => PHP [5] => PHP [7] => PHP [9] => PHP ) */ ### Push, Pop, Shift, and Unshift (Oh My!) These four commands are used to add or remove elements from arrays. | Function | Effect | | --------------- | ------------------------------------------------------------ | | array_shift() | Shifts an element off the beginning of array[5](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-53) | | array_unshift() | Prepends one or more elements to the beginning of an array[6](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-54) | | array_pop() | Pops the element off the end of array[7](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-55) | | array_push()| Pushes one or more elements onto the end of array[8](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-56) | You’ll probably notice that you can easily implement queues and stacks with these functions. The commands that remove an element from the array return it to you and shift all the elements down. Numeric keys are reduced until they start counting from 0 and literal keys are left untouched. two [1] => three [2] => four ) */ ## Comparing Arrays You saw earlier in the chapter that it is possible to use the equality == and identity === operators to compare arrays. When applied to arrays, the equality operator returns true if the arrays have the same keys and values, regardless of their type. The identity operator will only return true if the arrays have the same keys and values, they are in the same order, and they are of the same variable types. 'apple', 'b' => 'banana']; $b = ['a' => 'apple', 'd' => 'banana']; print_r(array_diff($a, $b)); print_r(array_diff_assoc($a, $b)); /* Array ( ) Array ( [b] => banana ) */ The result of array_diff() is an empty array, but array_diff_assoc() returns an array consisting of [b] => banana because the key for the value banana is b in the first array and d in the second. ### array_intersect() The function array_intersect() also takes a list of arrays as parameters. It calculates which valuesfrom the first array are also present in all the other arrays. chicken [3] => goose ) Note that the keys are preserved. ​array_intersect_assoc() includes an index check when matching elements. If you apply it to the arrays in the example, it will return an empty array. The return value is empty because, although the values in the arrays match, their indexes do not. ### User-Defined Matching Functions PHP provides functions that allow you to specify your own comparison function. Consider array_udiff() as an example. It takes a list of array parameters followed by a callable as the last parameter. Let’s consider a trivial example, where we want to compare the lowercase value of the arrays to each other. More realistic use-cases could involve more complicated operations, such as on objects for example. $b) { ​return 1; } else { ​return 0; } }); print_r($diff); This code outputs elements in the $net that don't have a matching animal in the list of $birds. We're using a custom function to do the comparison, which first converts both strings to lowercase. Array ( [0] => Dog [1] => Cat [4] => Hamster ) Note the following: - From the manual[9](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-57): “The comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.” - You can use closures as callables for any function that takes a callable as a parameter. - You can use lambdas as callables, also for any function that takes a callable as a parameter. In the example, we’re using a lambda. - The comparison function takes two arguments that will be the values to compare. There are PHP functions to allow you to specify your own callable to compare keys, values, or both. ### Quick List of Comparison Functions This table shows the arrays for performing the difference between functions. There are similar functions to perform the intersection. They have the same naming convention and parameters, so I'm not listing them here. | Function | Used For | | ------------------ | ------------------------------------------------------------ | | array_diff | Computes the difference of arrays[10](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-58) | | array_diff_assoc | Computes the difference of arrays with additional index check | | array_udiff | Computes the difference of arrays by using a callback function for data comparison[11](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-59) | | array_udiff_assoc | Computes the difference of arrays with additional index check and compares data by a callback function[12](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-60) | | array_udiff_uassoc | Computes the difference of arrays with additional index check and compares data and indexes by a callback function | Note that array_udiff_uassoc() takes two callable functions as parameters, one for the values and the last parameter for the indexes. Look at the manual page[13](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-61) and make sure you have studied all its related functions. ## Combining Arrays PHP offers some useful functions to help combine arrays. The combine_array($keys, $values) function creates an array by using one array for keys and another for its values. It will return FALSE if the number of elements in the arrays do not match, and otherwise will return an associative array. You can use array_replace($array1, $array2, ...) to sequentially replace values in an array with values from other arrays. It takes two or more arrays as parameters and processes them from left to right. It follows these rules to determine the final result: - If the first array has a key that is not in the second array, then the key-value pair is left untouched. - If the second array has a key that is not in the first array, then the key-value pair from the second array is inserted into the first array. - If the second value has a key that is also in the first array, then the value from the second array replaces the value in the first array. Let’s step through an example of using array_replace(): 'd', '1' => 'q']; $replaceTwo = [2 => 1, 1.3 => 'Z']; $output = array_replace($input, $replace, $replaceTwo); echo implode(", ", $output); // a, Z, 1, d I’ve placed this information into a table so that you can see how the rulesare applied. The function works from left to right, replacing each subsequent parameter with the previous array. | Key | $input | $replace | $replaceTwo | $output | | ---- | ------ | -------- | ----------- | ------- | | 0| a|| | a | | 1| b| q | Z | Z | | 2| c|| 1 | 1 | | 3| | d | | d | Note The string key 1 is cast to an integer and the float key 1.3 is also cast to integer. Both evaluate to 1 and so will replace the value in that position. The array_merge() function will merge one or more arrays. One might expect that it follows the same rules when merging as the + operator, but there are some situations where it behaves quite differently. Consider this example: 'One 0', // string 'a' => 'One a', // non-empty in One, but empty in Two 'Overwrite' => 'Not empty', ]; $arrTwo = [ 0 => 'Two 0', 1 => 'Two 1', 'b' => 'Two b', 'Overwrite' => '', ]; print_r($arrOne + $arrTwo); print_r(array_merge($arrOne, $arrTwo)); I’ll show you the output of this code in just a moment. There are two things that you should pay attention to in the code output: - The array_merge() function reindexes numeric keys, but the operator does not. - The array_merge() function will not overwrite a non-empty value with an empty value, but the operator will. As promised, here is the output showing the differences: Array ( [0] => One 0 [a] => One a [1] => Two 1 [b] => Two b ) Array ( [0] => One 0 [a] => One a [1] => Two 0 [2] => Two 1 [b] => Two b ) ## Splitting Arrays There are several functions that can be used to split up an array. The following table lists them. We'll look at some in detail in the book, but you should make sure that you go through the manual too. | Function | Used To| | ------------ | ------------------------------------------------------------ | | array_chunk | Split an array into chunks.[14](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-62) | | array_column | Return a single column from an input array, for example, an array of database query results. | | array_slice | Extract an array of the array. | | array_splice | Return a slice of the array and replace it with something else in the original array (the argument is called by reference).[15](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-63) | | extract| Create variables named for the keys of an array that contain the values from the array. Using this function can lead to murky code because it’s not immediately clear where a variable is defined. | | array_rand | Pick random keys of an array.| Of these functions, the only potentially tricky one is array_splice(). Not only does it return a value (the slice that was extracted), but because the input array is passed by reference, it also affects the array you call it on. To add further complication, you are optionally able to replace the slice that you extract from the input array with a replacement array. Let’s look at an example: 1 [1] => hello [2] => world [3] => 3 ) ## Destructuring Arrays The list() language construct is used to assign variables from an array based on their indexes. Here is a basic example of its usage: string(3) "one" [1]=> string(3) "two" [2]=> string(5) "three" } In PHP 5, the order is reversed and this outputs: array(3) { [2]=> string(5) "three" [1]=> string(3) "two" [0]=> string(3) "one" } ## Calculating with Arrays PHP offers several convenience functions that let you perform mathematical calculations on arrays without needing to iterate through them manually. | Function | Returns | | ------------------ | ----------------------------------------------------- | | array_count_values | How many times each unique value in the array appears | | array_product| The product of all the values in the array | | array_sum| The sum of all the values in the array | | count| How many elements there are in the array| | sizeof | This is an alias of count() | Note The product of an empty array is 1, not 0.[16](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-64) ## Iterating Through Arrays There are two ways to iterate through an array—by using a cursor and by looping through the array. ### Looping Through Arrays An enumerative PHP array can be looped through by incrementing an index counter, but this won't work for associative arrays. A better and more robust approach is to use the foreach() construct. It lets you quickly look at two possible syntaxes that foreach() uses and then move on. You should already be familiar with its usage if you're considering sitting for your exam, so this is for the benefit of programmers from other languages. 'apple', 'b' => 'banana', 'c' => 'cherry' ]; foreach($arr as $value) { echo $value . PHP_EOL; } foreach($arr as $key => $value) { echo $key . ' = ' . $value . PHP_EOL; } The first foreach() loop will traverse the array and pass the array values into the code block. The second foreach() loop traverses it and passes the key and value. By default, PHP the value passed into the code block of a foreach() loop is passed by value. If you change the value in the code block it will not have an effect outside of the code block. You can, however, mark the value to be passed by reference by prefixing it with an ampersand symbol. Caution Generally people will frown at you for using a reference in a foreach() loop. We’ll look at this in the following code example, which also demonstrates that the variable being declared in the foreach block becomes defined in the containing scope. After the loop finishes, it will hold the last value that it had in the loop. Relying on thisfeature makes your code harder to read, though. string(3) "cat" [1]=> string(13) "cheeseburgers" [2]=> string(6) "grumpy" } */ Note The each keyword, which could also be used to loop through an array, is deprecated in PHP 7.2.0 (so don't use it in PHP 7.1 either) ### Using Array Cursors Every array has a cursor, or pointer, that points at the current element. A number of PHP functions use the cursor to determine which element to operate on. Here are the basic cursor functions: | Functions | Performs | | --------- | ------------------------------------------------------------ | | reset | Moves the cursor to the beginning of the array[17](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-65) | | end | Moves the cursor to the end of the array | | next| Advances the cursor[18](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-66) | | prev| Advances the cursor| | current | Returns the value of the element the cursor points at | | key | Returns the key of the element the cursor points at| Objects can be iterated over using the same syntax, but it’s important to know that they implement an interface iterator. A less commonly seen use of a cursor is one such as this: 'apple', 'b' => 'banana', 'c' => 'cherry' ]; while (list($var, $val) = each($arr)) { echo "$var is $val" . PHP_EOL; } ​list() is a language construct that assigns variables from a supplied array. The each() function returns the current key and value pair from an array and advances the array cursor. ### Walking Through Arrays The array_walk() function applies a user callable to every element in an array. It takes two parameters—a reference to the array and the callable. The callable function will be passed two parameters. The first is the value of the element from the array and the second is its index. Some internal functions, such as strtolower() for example, will throw a warning if they receive too many parameters and so are not suitable as a callback for array_walk(). Note If you need your callback function to alter the value of the array, you should make sure to pass the first parameter by reference. Here is an example that will convert all the elements of an array to uppercase: 'apple', 'b' => 'banana', 'c' => 'cherry' ]; array_walk($arr, function(&$value, $key) { $value = strtoupper($value); }); print_r($arr); Note that I pass the value by reference into my lambda function, so changing it in the lambda will affect the $arr variable. If we had used strtoupper() as a callback, PHP would generate warnings. As an exercise try to work out why this is so. ## Sorting Arrays PHP offers several sort functions. They follow a naming convention whereby the base sort function is prefixed with r for reverse and a for associative. All sort functions take a reference to the array as their parameter and return a Boolean value indicating success or failure. | Function | Used For | | -------- | -------------------------------------------- | | sort | Sorting arrays alphabetically | | rsort| Reverse alphabetical sort | | asort| Associative sort | | arsort | Reversed associative sort | | ksort| Key sort | | krsort | Reverse key sort | | usort| User-defined comparison function for sorting | | shuffle | Pseudo-random sort | The associative sorts will sort by value and maintain the index association. Look at one of their manual pages[19](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-67) for an example. All of the functions (except usort()) accept an optional parameter to indicate the sort flag. These flags are predefined constants: | Flag | Meaning| | ------------------ | ------------------------------------------------------------ | | SORT_REGULAR | Compare items normally; don't change types.| | SORT_NUMERIC | Cast items to numeric values and then compare. | | SORT_STRING | Cast items to strings and then compare.| | SORT_LOCALE_STRING | Use locale settings to cast items to strings. | | SORT NATURAL | Use natural order sorting, like the function natsort().| | SORT_FLAG_CASE | Can be combined with SORT_STRING and SORT_NATURAL to sort strings case-insensitively. | ### Natural Order Sorting Natural ordering is a sort order that makes sense to human beings. It is an alphabetic sort order, but multiple digits are treated as a single character. The function natsort() does not take flags and is the same as sort() with the SORT_NATURAL flag set. As an example, let’s start with a string that looks sorted to our human eyes, shuffle it, and then use both forms of sorting to see how it comes out: a1 [2] => a2 [0] => a10 [4] => a11 [6] => a12 [3] => a20 [1] => a21 ) Array ( [0] => a1 [1] => a10 [2] => a11 [3] => a12 [4] => a2 [5] => a20 [6] => a21 ) ## Standard PHP Library (SPL): ArrayObject Class The SPL library includes the ArrayObject class that allows you to create objects from arrays. These objects can use the methods of the ArrayObject class, which are listed on the manual page. This lets you work with arrays as objects, as in this example from the PHP Manual[20](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-68): "lemon", "a" =>"orange", "b" =>"banana", "c" =>"apple"); $fruitArrayObject = new ArrayObject($fruits); $fruitArrayObject->ksort(); foreach ($fruitArrayObject as $key => $val) { echo "$key = $val\n"; } When constructing an ArrayObject, you pass in an input that can be either an array or an object. You can also optionally specify flags: | Flag | Effect | | --------------------------- | ------------------------------------------------------------ | | ArrayObject::STD_PROP_LIST | Properties of the object have their normal functionality when accessed as a list (var_dump, foreach, etc.). | | ArrayObject::ARRAY_AS_PROPS | Entries can be accessed as properties (read and write).[21](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-69) | These flags can be set with the setFlags() method, as in this example from the manual: 1, "oranges" => 4, "bananas" => 5, "apples" => 10); $fruitsArrayObject = new ArrayObject($fruits); // Try to use array key as property var_dump($fruitsArrayObject->lemons); // Set the flag so that the array keys can be used as properties of the ArrayObject $fruitsArrayObject->setFlags(ArrayObject::ARRAY_AS_PROPS); // Try it again var_dump($fruitsArrayObject->lemons); This example will output: ​NULL ​int(1) Chapter [4](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-48) Quiz Q1: Are PHP keys case-sensitive? What will the output of this script be? "apple", "B" => "banana"]; $arr2 = ["a" => "aardvark", "b" => "baboon"]; echo count($arr1 + $arr2); | This produces an error | | ---------------------- | | 2| | 4| | None of the above| Q2: What will this script output? 'apple', 'b' => 'banana', 'c' => 'cherry' ]; $keys = array_keys($arr); if (in_array($keys, 'a')) { echo "Found"; } | Found | | --------------------------------------------------- | | Nothing | | Warning: in_array() expects parameter 2 to be array | | None of the above | Q3: What will this script output? 1, "oranges" => 4, "bananas" => 5, "apples" => 10); $fruitsArrayObject = new ArrayObject($fruits); $fruitsArrayObject->setFlags(ArrayObject::ARRAY_AS_PROPS); // Try to use array key as property var_dump($fruitsArrayObject->lemons); | This produces an error | | ---------------------- | | int(1) | | string(6) "lemons" | | None of the above| Q5: What will this script output? property = "Hello World"; // object assignment is by reference $b = $a; $b->property = "Assigned by reference"; // $a has also changed because $b is a pointer to $a var_dump($a); /* object(stdClass)#1 (1) { ["property"]=> string(21) "Assigned by reference" } */ We’ll look at this in more detail later when we learn about the clone keyword in the section on “Working with Objects”. ## Autoloading Classes Classes should be defined before they are used, but you can use autoloading to load classes when they are required. Together with coding standards like PSR4 that govern where PHP will look for a class, this can be an indispensable feature. Tip You won’t be asked questions about PSR4 in the Zend examination, but the standards put forward by the FIG group are very important in the PHP world. Autoloading in PHP is accomplished the the spl_autoload_register() function. A PSR4 compliant implementation is given on the PHP FIG group web page,[1](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-157) but let’s look at a simpler demonstration from the PHP manual[2](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-158) for an example: name = $name; } // public visibility by default function getName($name) { return $this->name; } } Methods can access non-static object properties using the $this pseudo-variable. The $this pseudo-variable is defined in objects and refers to the object itself. Static methods are declared without an object having been instantiated and so $this is not available. ## Static Methods and Properties Declaring a method or property as static makes it available without needing a concrete implementation of the class. Because a static method can be called without an instantiated object, the pseudo-variable $this is not accessible in these methods. Static methods and properties may have any visibility modifier applied to them. You should not call a non-static method statically. This will generate a deprecation warning: someFunction(); // Hello World When we reference a static property from within the class, we can use self, parent, or static to refer to it. We’ll deal with the static keyword in the section on “Late Static Binding” in this chapter. When referencing the static class member from outside the class, you prefix the scope resolution operator with the name of the class. In the previous example, we referenced the static function with MyClass::sayHello(). ### Static Properties Static properties are also declared with the static keyword and can be accessed with the scope resolution operator. For example: [A::class]]); // this creates __PHP_Incomplete_Class because the class doesn't match $b = unserialize($stored, ['allowed_classes' => [B::class]]); // this creates __PHP_Incomplete_Class because no classes are allowed $c = unserialize($stored, ['allowed_classes' => false]); // this works because all classes are allowed $d = unserialize($stored, ['allowed_classes' => true]); // this generates a warning because the parameter type is incorrect $e = unserialize($stored, ['allowed_classes' => 'Not boolean or array']); Caution Do not use serialize() to pass data to the user. Rather use json_encode! Why not? Because of the mantra “all user input is potentially evil”. You don’t want to give users the chance to run their code through unserialize(). ### Casting Between Arrays and Objects We covered casting variables in the chapter on PHP basics. We should note that it is also possible to use the same syntax to cast between an array and an object. Let’s look: 'value', 'nested_array' => [ ​'another_key' => 'different_value' ​] ]; $object = (object)$array; var_dump($object); In this example, I used the (object) casting syntax to force the array to become an object. PHP will produce an object of StdClass that has properties corresponding to the keys of the array. This code outputs: object(stdClass)#1 (2) { ["key"]=> string(5) "value" ["nested_array"]=> array(1) { ["another_key"]=> string(15) "different_value" } } Note The nested array is not converted to a nested object. It is possible to cast an object to an array using the (array) casting syntax. If we were to run the command assert((array)$object === $array); at the end of that code listing, the code would complete without errors because the assertion passes. ### Casting Objects to String You can define how your object will be cast to string by declaring the __toString() method. PHP will call this method and return its result when it tries to cast your object to a string. firstName; } } $user = new User; // 'echo' expects a string type so PHP will implicitly cast the object to string echo $user; // Example Thislets you build and format a string that is meaningful for your object. If you do not declare this method on your object, then PHP will generate a catchable fatal error telling you that it cannot convert an object to a string. ### Class Aliases PHP allows you to create aliases for classes using the class_alias() function. This function accepts three parameters—the original class name, the alias to create for it, and an optional Boolean value to indicate if the autoloader must be called if the class is not found. At first blush, it may not be immediately apparent what the use-case for aliasing a class might be. Their chief use-case is for conditionally importing namespaces. The use keyword is processed at compile time and not run time. This means that it is impossible to use conditional logic to change which namespaces to import. The class_alias() function lets you conditionally import namespaces. For example, you may want to swap which class to use to cache your database depending on whether the memcached extension is available. In the following code, we would not be able to import alternative classes with the use keyword, but by using class aliasing, we can change the class that cache refers to. name = $name; ​} } $user = new User('Alice'); Here we are passing string "Alice" to the constructor function. A practical example of this would be for dependency injection.[4](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-160) ## Inheritance PHP supports inheritance in its object model. If you extend a class then the child class will inherit all of the non-private properties and methodsof the parent class. In other words, the child will have the public and protected elements of the parent class. You can override them in the child class, but they will otherwise have the same functionality. PHP does not support inheriting from more than one class at a time. The syntax to cause a class to inherit is very simple. When declaring the class, we simply indicate the name of the class it is extending, as in this example: sayHello(); // ParentClass In this example, the ChildClass is declared as extending the ParentClass. It inherits the sayHello() method. If we were to define a GrandChildClass that inherits from the ChildClass then it too would inherit all the ParentClass methods. In fact, any class in an inheritance chain will inherit all the methods and properties of its ancestors. Note The magic constant __CLASS__ gives the name of the class that is currently being executed. We’re calling the inherited method in the child class, but it is executing the function in the parent class and so reporting that the class name is ParentClass. ### The final Keyword PHP 5 introduced the final keyword. You can apply it either to a whole class, or to specific methods within a class. The effect of the final keyword is to prevent classes from being extended or methods from being overridden. The visibility of all final properties and methods ispublic. Marking classes or functions as final helps you avoid mistakenly changing behavior when you extend a class. PHP will issue a fatal error if you try to override a final method in a child class or if you try to declare a class that extends a class that is marked final. You mark a class or method as final by using the final keyword in front of its definition, like this example where I’m marking the function as final: class Employee { final public function calculateWage(float $hourlyRate, int $numHoursWorked) { ​return $hourlyRate * $numHoursWorked; } } Let’s look at another example that shows the error produced and highlights the usefulness of the keyword. The code listing in the following example does not have any uses of the final keyword and so will run without error and calculate a rather generouswage packet for the employee. I’ve commented two lines to show the error that will be thrown if we mark the class or method as final, respectively. employeeName === 'Andrew') { ​return 1000000; ​} ​return $hourlyRate * $numHoursWorked; } } $oops = new Oops; $oops->employeeName = 'Andrew'; echo $oops->calculateWage(10.00, 50); Note This is somewhat different from the use of final in Java, the PHP equivalent of the Java final keyword is const. ### Overriding A child class may declare a method with the same name as the parent class, providing that the method is not marked final in the parent. The method parameter signature in the child must be like the parent; for example, the following code will generate a warning that the child declaration needs to be compatible with the parent: girlDescendingStairs(); // Whee! I define a new class which I’ve imaginatively called Foo that extends the abstract class. I’ve implemented the abstract method girlDescendingStairs" and I’ve changed the visibility from protected to the less restricted scope, public. I haven’t overwritten the non-abstract methods that the abstract class defined. The Foo class has no abstract methods and so I can construct an object from it. Notice that when I do so, the parent’s constructor is called and so Foo wrongly reports that it cannot be constructed. ## Anonymous Classes PHP 7 introduced anonymous classes, which allow you to define a class on the fly and instantiate an object from it. Here’s a simple example of using an anonymous class: getMethods()); The parameter passed to the constructor of the reflection class is either the string name of the class, or a concrete instantiation (object) of the class. The ReflectionClass object has a few methods that allow you to retrieve information about the inspected class. In the previous example, we are outputting an array of all the methods that the Exception class has. ## Type Hinting Type hinting allows you to specify the variable type that a parameter to a function is expected to be. In the following example, we specify that the parameter $arr being passed to the printArray() function must be an array. " . print_r($arr,true) . ""; } // The parameter to the function must be a class that implements the PaymentProvider interface function sendNotificationToPaymentProvider(PaymentProvider $paymentProvider) { $paymentProvider->contactGateway($messageParameters); } function sayHello(string $name) { echo "Hello " . $name; } In PHP 5, if you pass a parameter of the wrong type, then a recoverable fatal error will be generated. In PHP 7, a TypeError exception is thrown. As of PHP 7 type hinting is being referred to as “type declarations”. I’m going to use this new nomenclature but the terms are interchangeable within the context of PHP. You can specify composite types, callables, and scalar variable types as type hints. Additionally, the NULL type hint can be used if NULL is used as the default parameter for a function. balance = 100; // Cannot set balance to 100No value echo $myAccount->nonExistingProperty; The __get() method is passed the name of the property that was being looked for. You can return a value for the missing property in the method, or handle it how you like. In the example, the commented code can be replaced with logic to handle the missing property, and properties that don’t exist will appear to be set to No value. An additional parameter, the $value, is passed to __set(). ### __isset and __unset The __isset() method is triggered by calling the isset() function or empty() on an inaccessible property. The __unset() method is triggered by calling the unset() function on an inaccessible property. Both methods accept a string parameter that contains the name of the property that was being passed as a parameter to the function. You can use these magic methods to allow the isset(), empty(), and unset() functions to work on private and protected properties. ### __call and __callStatic These magic methods are called if you try to call a non-existing method on an object. The only difference is that __callStatic() responds to static calls while __call() responds to non-static calls. honesty(); // Politician has no honesty method In both cases, the magic method is passed a string containing the name of the method that the call is trying to find, and an array of the argumentsthat were passed. ### __invoke The magic method __invoke() is called when you try to execute an object as a function. $this->oil ​]; } } $country = new Dictatorship(); var_dump($country); /* object(Dictatorship)#1 (1) { ["oil"]=> string(4) "Lots" } */ This example will prevent the $wmd variable from being included in the var_dump(). ### More Magic Functions We have dealt with the __construct() and __destruct() functions in the section on “Constructors and Destructors”. We have dealt with __sleep() and __wake() in the section on “Serializing Objects”. We looked at __clone() when discussing “Copying Objects” and __toString() in the section named “Casting Objects to String”. ## Standard PHP Library (SPL) The standard PHP library is a collection of classes and interfaces that are recipes for solving common programming problems. It is available and compiled in PHP from version 5.0.0. The classes fall into categories. For a complete list of the classes, refer to the PHP Manual on SPL.[6](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-162) | Category | Used for | | -------------------------- | ------------------------------------------------------------ | | Data Structures| Standard data structures, like linked lists, doubly linked lists, queues, stacks, heaps, etc. | | Iterators|| | Exceptions || | File Handling|| | ArrayObject | Accessing object with array functions. | | SplObserver and SplSubject | Implementing the observer pattern. | SPL also provides several functions. They mostly fall into broad reflection and autoloading categories. ### Data Structures The first category of functions is data structures. If you’re familiar with data structures already, you’ll be pleased to know that the SPL implements a variety of them. These include doubly linked lists, heaps, arrays, and maps. Data structures are widely useful in programming algorithms. ### Iterators Iterators allow you to traverse over objects and collections. Iterators maintain a cursor that points to an element. PHP iterators will allow you to advance or rewind the cursor through all of the elements in the container. They will also let you perform other actions, for example, the ArrayIterator will let you perform sorts on arrays. Without the classes provided by PHP, you would need to implement these iterators yourself, but luckily all of that hard work has been done by the kind authors of PHP. There’s quite an extensive list of iterators. I shouldn’t imagine that you’ll need to be able to list them, but you should know that they’re part of the SPL. They will at a minimum provide cursor movement abilities and possibly some extra functionality. ### Exceptions The SPL also includes standard Exception classes. It’s good practice to throw exceptions that are specific to the type of error that has occurred. This makes it easier to code catch blocks that will properly deal with the exception. The SPL introduces some exception classes that make it a lot more convenient for you to throw specific exceptions. SPL exceptions fall under two categories—logic exceptions and runtime exceptions. Each of these categories has a number of exception classesthat focus on specific sorts of errors that can occur. You should at least be able to recognize them if they come up in a question. #### Logic Exceptions - ​LogicException (extends Exception) - ​BadFunctionCallException - ​BadMethodCallException - ​DomainException - ​InvalidArgumentException - ​LengthException - ​OutOfRangeException - ​Runtime exceptions - ​RuntimeException (extends Exception) - ​OutOfBoundsException - ​OverflowException - ​RangeException - ​UnderflowException - ​UnexpectedValueException ### File Handling SPL also offers classes to help with handling files. The SplFileInfo class offers a high-level object-oriented interface to information for an individual file. It has methods that you can use to find the name, size, permissions, and other attributes for a file. You can also tell if the file is a directory, if it’s executable, and a lot of other functions. The SplFileObject class offers an object-oriented interface for a file. You can use it to open and read from a file. There are methods to advance or rewind through the file, seek to specific positions, and other functions that are useful when you’re processing a file. The SplTempFileObject class offers an object-oriented interface for a temporary file. You can use this file as you would any other output file, but it is deleted after your script finishes. You could use this when image processing or verifying file uploads, for example. ### ArrayObject The SPL also includes miscellaneous classes and interfaces. The first of these, the ArrayObject, allows objects to work as arrays. When you construct an ArrayObject, you can pass an array as its parameter. The resulting object will have methods on it that mimic the PHP array functions. There are quite a few limitations to the ArrayObject but one of the strengths is that you’re able to define your own way of iterating through it. ### Observer Pattern Finally, let’s look at two interfaces included in the SPL—SplObserver and SplSubject. Note that these are interfaces and not classes, so you’ll need to implement the actual behavior. Together these two interfaces implement the observer pattern. The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods. This pattern is mainly used to implement distributed event handling systems. Using these interfaces will make your code more portable because other libraries will be able to interact with your subject and observers. ## Generators Generators provide you with an easy way to create iterator objects. The advantage to using an iterator with a generator is that you can build an object that you can traverse over without needing to calculate the entire data set. This saves processing time and memory. The use-case could be to replace a function that normally returns an array. The function would calculate all the values, allocating an array variable to store them, and return the array. A generator only calculates and stores one value and yields it to the iterator. When the iterator requires the next value, it calls the generator. When the generator runs out of values, it can either just exit or return a final value. Generators can be iterated over as with any iterator, as in this example: $value; } ### Yielding NULL Calling yield without an argument causes it to yield a NULL value with an automatic increasing sequential key. ### Yielding by Reference Generator functions can yield variables by reference and the syntax to do so is to prepend an ampersand to the function name. $value) { echo $key . ' => ' . $value . PHP_EOL; } echo $gen->getReturn(); /* 0 => wheat 1 => flour cupcake */ Thissyntax makes it explicit what the return value of the generator was. Without it, you would need to assume that the last yielded value was the return value. ### Generator Delegation Generator delegation let’s you delegate the responsibility for processing values to another traversable object or array. The syntax to do so is yield from : trait methods > inherited methods ### Conflict Resolution PHP will generate a fatal error if two traits attempt to insert a method with the same name unless you explicitly resolve the conflict. PHP allows you to use the insteadof operator to specify which of the conflicting methods you want it to use. This lets you exclude one of the trait methods, but if you want to keep both methods, you need to use the as operator. The as operator allows you to include one of the conflicting methods, but use a different name to reference it. Here is a rather long example that shows this usage: makeNoise(); // Purr $obj->wantWalkies(); // Yes please! $obj->kittyWalk(); // No thanks! Note It is not enough to use as by itself. You still need to use insteadof to exclude the method you don’t want to use, and you can only then use as to make a new way to reference the old method. ### Visibility You can apply a visibility modifier to functions by extending the use keyword, as in this example: myFunction(); // PHP Fatal error: Call to protected method We specify that the method should be made protected in the class, even though it is declared as public in the trait. You can include multiple functions in the block, each of which may have its own visibility. Chapter [5](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-156) Quiz Q1: Which of these is NOT a valid PHP class name? | exampleClass | | ------------------------------ | | Example_Class| | Example_1_Class| | 1_Example_Class| | They are all valid class names | Q2: What will the property $name contain after this code is run? name = "Asleep"; } public function __unserialize() { ​$this->name = "Rested"; } } $obj = unserialize(serialize(new SleepyHead())); | Dozy | | ------------------- | | Asleep| | Rested| | This code won’t run | Q3: Which of the following statements can we replace the commented line with in order for the script to output "Castor"? name = "Castor"; $twin->name = "Pollux"; echo $star->name; // must be Castor | $twin = $star; | | ------------------------- | | $twin = clone($star); | | $twin &= $star; | | $twin = new clone($star); | Q4: Let’s say that object A has a property that is an instance of object B. If we clone object A, then will PHP also clone B, which is one of itsproperties? | Yes| | ------------------------------------------------------------ | | No | | You can’t clone objects that contain references to other objects | Q5: You cannot declare two functions with the same name. Choose as many as apply. | True | | ------------------------------------------------------------ | | False; you can declare them in different namespaces| | False; you can declare them with different number of parameters in their constructor and PHP will pick the definition that matches your instantiation | | False; you can declare them in different scopes| Q6: When you call the json_encode function on an object to serialize it, which magic method will PHP call? | __sleep | | ------------- | | __wake | | __get | | __clone | | None of these | Q7: True or false: Interfaces can only specify public methods, but your class can implement them however you like. | True | | ------------------------------------------------------------ | | False; interfaces can specify any visibility | | False; you cannot change the visibility when you implement at all | | False; you can only change the visibility to one that is less visible | Q8: What will the output of this code be? prepare("SELECT * FROM REGISTRY where name = ?"); ​$stmt->bindParam(':name', $_GET['name'], PDO::PARAM_STR, 12); ​$stmt->execute(); Note The PDO::prepare() function returns an object of type PDOStatement. We are using the GET variable directly, so we don’t need to escape it because it is being bound as a variable with PDOStatement::bindParam() and cannot alter the syntax of the SQL that is going to be run. Other database drivers in PHP also support prepared statements. Here is an example from the manual for MySQL[5](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-502): ​ /* Prepared statement, stage 1: prepare */ ​ if (!($stmt = $mysqli->prepare("INSERT INTO test(id) VALUES (?)"))) { echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error; ​ } ​ /* Prepared statement, stage 2: bind and execute */ ​ $id = 1; ​ if (!$stmt->bind_param("i", $id)) { echo "Binding parameters failed: (" . $stmt->errno . ") " . $stmt->error; ​ } ​ if (!$stmt->execute()) { echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error; ​ } ### Escaping A less effective way to mitigate SQL injection is to escape special characters before sending them to the database. This is more prone to error than using prepared statements. If you are going to try escaping special characters, you must use the database specific function (e.g., mysqli_real_escape_string()) or PDO::quote() and not a generic function like addslashes(). ### General Principles You should also always connect to the database with a user who has the least amount of privileges that are required for the application to function. Never allow your web application to connect to the database as its root user. If you host multiple databases on your server, use a different user for each database on your server and make sure that their passwords are unique. This will help prevent a SQL injection attack on one site from affecting the databases of other sites. Make sure that you’re using an up-to-date version of MySQL and enforce the use of a character set in the client DSN. There is a very subtle way to use mismatching character sets in certain vulnerable encoding schemes to deploy a SQL injection; see the second answer (not the accepted one) on this StackOverflow article[6](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-503) for an exposition. ## Remote Code Injection Remote code injection is an attack where an opponent can get the server to include and execute their code. ### Functions That Evaluate Strings as Code Certain functions like eval(), exec(), and system() are susceptible to remote code injection exploits. If you are executing a variable that includes user input, they will be able to inject commands using escape characters. You can mitigate this by using escapeshellargs() to escape the arguments passed to the shell command. The escapeshellcmd() function will escape the shell command itself. Tip If you’re not explicitly using these functions, you should disable them in your php.ini. It’s not foolproof, but it can help. The assert() function is used to make sure that a certain condition is true and take some action if it is not. It's useful for debugging, but you should turn it off for production. You can use the assert_options()[7](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-504) function to configure how assert behaves and to turn it off. If you pass a string value to assert() then PHP will evaluate the string as if it were PHP code. This would let an attacker execute code on your server if they could control what argument you pass into assert(). ​ (Greater than) | > | Both functions take a flag as their second parameter. You should make sure that you know at least these three flags as they are important for escaping JavaScript you’re outputting: | Flag | Description | | ------------ | ----------------------------------------- | | ENT_COMPAT | Converts double quotes, not single quotes | | ENT_QUOTEs | Converts double quotes and single quotes| | ENT_NOQUOTES | Does not convert any quotes | When escaping a JavaScript string, you should use the ENT_QUOTES flag. The encoding of the string can be specified in the third parameter. In PHP 7.1, the default encoding for both functions is UTF-8. ### Avoid Log Poisoning If you’re logging error messages, information messages, and the like, you need to take some precautions with what you log. Obviously, you must never log sensitive information like user passwords or credit cards. If you’re passing this to a logging function, then make sure you obfuscate it. So, a credit card number would be a sequence of asterisksin your log file, rather than the actual number. Make sure that you filter out executable code and personal information before logging it. You should also be aware of how a log poisoning attack works. The vulnerability rests on your code improperly including local files. If you allow user input to determine which file is included then an attacker could manipulate that input to include a log file. If the log file contains malicious code then it will be interpreted and run. All that an attacker needs to do is get their code into your log file, which can be very easy to do. For example, they can poison your web server log by crafting a request that will inject a string containing the commands they want to run into the log. As another example of the attacker can SSH onto your server and use malicious code as their username to poison your authentication log file. To help you understand the impact, let’s run through an example of an exploit. Let’s assume that your code is running on your localhost and is vulnerable to local file inclusion and accepts the name of an image that needs to be displayed. First, we use the command nc localhost 80 to connect to the web server. We then issue the following request to the server: ​GET / HTTP/1.1

​Host: localhost

Apache will write a line in the log file that looks something like this:

​127.0.0.1 - - [08/Apr/2016:13:57:38 +0000]

​"GET /

​HTTP/1.1" 400 226

​""

​""

I'm splitting my log entry over multiple lines but obviously in your log file, it will all be on the same line.

The next step of the exploit is to issue a request to the site that includes the log file (this requires there to be such a vulnerability in your site).

http://localhost/?file=/var/log/apache2/access.log&cmd=ls-la

Quite a lot needs to go wrong for you to be vulnerable to this:

  • The web server user needs read access to the targeted log file
  • Your code must allow the attacker to include a targeted file
  • You cannot have disabled exec, passthru, and system in your configuration

Encryption and Hashing Algorithms

Encryption and hashing are different concepts and you should make sure you understand the difference. Encryption is a two-way operation; you can encrypt and decrypt. Hashing is a one-way operation and by design it isdifficult or time-consuming to take a hash and reverse it to the original string.

You should store passwords in the database as hashes. This way, if attackers get a copy of your database, they are still unable to obtain user passwords unless they can reverse the hash. Typically, reversing the hash will take a significant amount of time, and hopefully you will have enough time to notice the breach of security and alert your usersthat they need to change their passwords.

The amount of time that it takes to calculate a hash will determine how long a hacker will take to guess passwords by brute force.

Encryption in PHP

Encryption in PHP is provided by the mcrypt module, which needs to be installed and enabled separately. The mcrypt module makes available a wide range of encryption functions and constants.

The algorithms that are available are dependent on the operating system on which PHP is installed. You should not attempt to write your own implementation of an encryption algorithm.

The Zend certification examination does not have a heavy emphasis on encryption.

Hash Functions

Older hashes like MD5 and SHA1 are very quick to calculate and so you must not use them in any place where security is involved. They are still very useful in other areas of programming, but not in any place where you’re relying on them being a one-way operation.

PHP 5.5.0 introduces the password_hash() function, which provides a convenient way to generate secure hashes.

For older versions of PHP, you should use the crypt() function.

By default the password_hash() function uses the bcrypt algorithm to hash the password. The bcrypt algorithm has a parameter that includes how many times it should run on the password before returning the hashed result. This is referred to as the “cost” of the algorithm.

By increasing the number of times that the algorithm must run, you can increase the length of time that it takes to calculate a hash. Thismeans that as computers get faster, you can increase the number of iterations in your bcrypt algorithm to keep your passwords secure from brute force attacks.

You can use the password_info() function to retrieve information about how a hash was calculated. Thisfunction will tell you the name of algorithm, the cost, and the salt.

The password_needs_rehash() function will compare a hash against the options you specify to see if it needs to be rehashed. This will let you change the algorithm used to hash your passwords, for example increasing the cost over time.

Secure Random Strings and Integers

PHP has two functions that allow you to conveniently generate cryptographically secure integers and strings. These functions will work on any platform where PHP runs.

Function Parameters Returns Description
random_bytes Int $length String of bytes Generates a random string that is $length bytes long
random_int Int $min, int $max Random integer Generates a random integer in the range specified by $min and $max

Here is an example of using random_bytes:

​<?php

​// get a string that contains 8 random bytes

​$randomBytes = random_bytes(8);

​$printableVersion = bin2hex($randomBytes);

​echo $printableVersion; // d7e263202be1b99b

The string that PHP generates will not necessarily be printable, so I'm using the bin2hex() function to convert it to a hexadecimal string. Hexadecimal requirestwo characters to display a byte so the string that we output at the end is 16 characters long (twice the number of random bytes we generated).

Salting Passwords

A salt string is an additional string that is added to the password. It should be randomly generated for every password. It is used to help make dictionary attacks and pre-computed rainbow attacks more difficult.

You can specify a salt for the password_hash() function, but if you omit it then PHP will create one for you. The PHP Manual notes that the intended mode of operation is for you to let it create the random salt for the password.

The crypt() function accepts a salt string as a second parameter, but will not automatically generate a salt if you don’t provide your own. PHP 5.6.0+ will issue a notice if you fail to provide a salt.

Checking a Password

If it is possible for an attacker to accurately measure the time it takes to run your password checking routine, they will be able to glean information that can help them in breaking the password. These attacksare referred to as timing attacks.

The PHP 5.5.0 password_verify() function is a timing attack[9](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-506)-safe way to compare hashes created by password_hash().

If you’re unable to use this function, you will need to calculate the hash for the password supplied by the user and then compare the hash against the one stored. Comparing the hashes is vulnerable to timing attacks.

PHP 5.6.0 introduced the hash_equals() function, which is a timing attack-safe way of comparing strings. You should use this function when comparing crypt() generated hashes.

A Quick Note on Error Messages

You should never confirm to a person that they have entered an incorrect username. Your error message should be that they have entered either an incorrect username or password. The less information you give to an attacker, the longer it will take for them to gain access to your system.

File Uploads

File uploads are a major risk for a web application and need to be secured in several ways.

Recall that the $_FILES[] superglobal contains information about the files that were uploaded by the client. You should treat everything in this array as suspicious and make sure that you manually confirm every piece of information.

The way PHP handles file uploads is to save them to a temporary directory. You can operate on them there and then move them to the location where you want them.

You should check that the file you’re working with is a valid uploaded file and that the client has tried to forge its filename and location in the temporary folder.

Use the is_uploaded_file() function to make sure that the file you’re referencing was actually uploaded. Use the move_uploaded_file() instead of other methods to move it from the temporary directory to your final location.

When referring to a file, use the basename() function to strip out paths to prevent a person from spoofing the filename.

Don’t trust the MIME type specified by the user. Ignore the MIME type supplied by the user and use finfo_file() to determine the MIME type if you need it.

If you’re allowing a user to upload an image, you should use a GD image function like getimagesize() on it to confirm that it is a valid image. If this function fails, then the file is not a valid image.

Generate your own filename to store the file as and do not use the one supplied by the user. Using a random hash for the filename and setting the extension manually by inspecting the MIME type is strongly suggested.

Make sure that the folder where you are storing the files only allows access to the web server user.

If you don’t need to serve the files that are uploaded, then keep the uploads folder outside of the document root.

Database Storage

In addition to avoiding SQL injection, you should apply some security principles to how you interact with the database.

You should separate your database servers for your different code environments. Your QA, test, development, and production servers should all use different database servers and should not be able to access each other’s databases.

You must prevent the Internet from having access to your database server.

This can be accomplished by using a firewall to close the port from outside traffic, using a private subnet that has no route to the Internet, or configuring your database server to listen only to specific hosts.

It’s not sufficient to change the port that your database listens on. I’d go as far as to say it’s not worth bothering because it’s not even a speed bump to an attacker and just makes your server environment harder for your colleagues to use.

If you run several applications on a single database server, make sure that each application has its own username and password on the server. Each application user should have only the least amount of privileges it needs and should never be able to read another applications’ databases.

Avoid using predictable usernames and make sure that you use secure passwords. For example, I usually use a randomly generated version 4 UUID as a password.

Encrypt sensitive data with mcrypt() and mhash() before placing it into the database.

You should examine your database logs from time to time. You’ll be able to spot attempted injection attacks and other patterns that will let you identify breaches or tighten areas of code.

Avoid Publishing Your Password Online

A good piece of advice is to avoid publishing your database or API credentials online where people can read them. Okay, I’m being facetious, but seriously when would you be likely to publish all your access credentials for the world and his dog to read?

One time you could do this is when committing to a Git repository and pushing it to a service like GitHub or Bitbucket.

Make sure that any configuration files are ignored by your version control system and are never committed or pushed to upstream repositories. There are bots that scrape GitHub for credentials that will punish you for these mistakes.

Just as an aside related to this link, you should not hard-code Amazon credentials into an application. Rather, set an IAM role that allowsaccess to the service you want to use and apply the role to your VM.

Chapter [6](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-11) Quiz

Q1: The recommended production setting for the display_error configuration setting is On.

True
False

Q2: Using HTTPS to encrypt your login page will help to prevent session hijacking and session fixation.

True
False *

Q3: You can force sessions to be contained exclusively in cookies by using the _____________ configuration setting.

session.cookie_secure
session.use_cookies
session.use_trans_sid
None of the above

Q4: CSRF involves an attacker tricking the user's browser or device into making a request without them knowing. It exploits the trust that the server has in the browser. You can avoid it by including a CSRF token in your form that increases by one every time a visitor loads the page.

True
False

Q5: Both the crypt() and the password_hash() functions allow you to specify the salt, but will generate a properly random salt for you if you do not.

True
False

Q6: The browser determines the file type by making an OS call and sends thisinformation with the request. You can trust this to determine the extension to use when storing the file.

True
False

Q7: Because PHP deletes the temporary file when it finishes running, you should first make sure that you use the copy() function to place the temporary file in a permanent location.

True
False

Q8: By default, PHP is configured to be able to include source code that is stored on a URL.

True
False

Q9: A sufficient counter-measure to prevent XSS is to use the strip_tags() function before your content.

True
False

Q10: The open_basedir configuration setting has no effect unless PHP safe mode is on. It restricts which directories PHP can access.

True
False

Footnotes

[1](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-507)

https://github.com/php/php-src/blob/master/php.ini-production

[2](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-508)

https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#passing-uncontrolled-requests-to-php

[3](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-509)

https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/

[4](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-510)

https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

[5](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-511)

https://dev.mysql.com/doc/apis-php/en/apis-php-mysqli.quickstart.prepared-statements.html

[6](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-512)

https://stackoverflow.com/a/12202218/821275

[7](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-513)

https://secure.php.net/manual/en/function.assert-options.php

[8](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-514)

https://github.com/msigley/PHP-HTTP-Tarpit

[9](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-515)

https://en.wikipedia.org/wiki/Timing_attack

© Andrew Beak 2017

Andrew BeakPHP 7 Zend Certification Study Guide[https://doi.org/10.1007/978-1-4842-3246-0_7](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-0)

7. Data Formats and Types

Andrew Beak1

(1)

Grafham, Cambridgeshire, UK

This chapter is split into six broad areas:

  • XML
  • SOAP
  • REST web services
  • JSON
  • Date and time
  • PHP SPL data structures

Although thistopic is not one of the three high importance areas for the Zend exam, you can expect to be asked a couple of relatively detailed questionsfrom this section.

XML

XML stands for eXtensible Markup Language and is a way to store data in a structured manner. An advantage of using XML is that it is a well recognized data standard and so is a convenient way to exchange data between systems.

In the industry, there has been a shift away from XML and toward JSON as a data exchange process, but XML is still relevant to everyday practice and is part of the Zend examination.

The Basics of XML

This isn’t an introductory book on PHP, so I won’t introduce all the elements of XML in excruciating detail. This book would be far too long if we went into that level of detail. Make sure that you are at least familiar with all the terms in the following table, because we’ll be using them as we examine the XML processing capability of PHP.

Term Description
SGML Standardized General Markup Language. XML is a subset of this.
Document Type Declaration The DTD defines the legal building blocks of an XML document structure with a list of legal elements and attributes.
Entity An entity can declare names and values that are not permitted in the rest of the XML document. For example, HTML declares < as an entity to represent the less than symbol <. These declarations can also be used as shortcuts and to maintain consistency of spelling and value throughout a document.
Element Elements are the basic building blocks of an XML document. Elements can be nested and contain elements, or they can contain a value. Elements may have attributes.
Well-formed A well-formed document in XML is a document that adheres to the syntax rules specified by the XML 1.0 specification in that it must satisfy both physical and logical structures.[1](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-1)
Valid An XML document validated against a DTD is both “Well Formed” and “Valid”.

If you’re at all shaky about these definitions, then please make sure that you read a comprehensive tutorial on XML and read the linked footnotes from this section.

Well-Formed and Valid

Let me expand on what these terms mean because it’s important to know the difference.

A document is well-formed if:

  • It has a single root element
  • Tags are opened and closed properly
  • All its entities are well-formed, according to this list:
    • They contain only properly encoded Unicode characters
    • No syntax marks like < or & appear
    • Tag names must match exactly and may not contain symbols

A document is valid if it is well-formed and conforms to the DTD.

Note

PHP does not require XML documents to be valid but it does require them to be well formed to parse them with standard libraries.

XML Processing Instructions

Processing instructions allow documents to contain instructions for applications. They are enclosed in marks and look like this, for example:

One use-case could be to inform an application that an element is to be a particular data type, as in this example:

The most common usage is to include an XSLT or CSS stylesheet, like so:

XML Transformations with PHP XSL

The PHP XSL extension allows PHP to apply XSLT transformations.

Although this is commonly used to apply stylesheets, it is important to know that many other forms of transformation are possible.

XSL is a language for expressing stylesheets for XML documents. It is like CSS in that it describes how to display an XML document.

XSL defines XSLT that is a transformation language for XML documents that allows XML documents to be processed into other documents.

An XSLT processor takes an input XML file, some XSLT code, and produces a new document. Figure [7-1](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-2), taken from Wikipedia Creative Commons, illustrates this.

A456636_1_En_7_Fig1_HTML.jpg

Figure 7-1.

​XSLT processor

A use-case for this could be to create an XHTML document that can be rendered by a browser.

Input XML would be received from a PHP program that includes processing instructions about where to retrieve an XSL stylesheet. The browser would retrieve this stylesheet and apply the XSLT code in it to produce the XHTML.

Acronym What It Is
XSL Language to express stylesheets
XSLT Transformation language to process XML into another XML document

The PHP manual[2](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-3) has a simple example of how to use PHP to transform an XML file using an XSL:

load("collection.xsl"); $xmlDoc = new DOMDocument(); $xmlDoc->load("collection.xml"); $proc = new XSLTProcessor(); $proc->importStylesheet($xslDoc); echo $proc->transformToXML($xmlDoc); ### Parsing XML in PHP There are two types of XML parsers available in PHP. There are several PHP extensions that parse XML, but they all fall under one of these two types. All the PHP XML extensions use the same underlying library, so it is possible to pass data between them. All XML routines require both the LibXML extension and the Expat library to be enabled. These are both enabled by default in PHP. #### Tree Parsers Tree parsers attempt to parse the entire document at once and transform it into a tree structure. It should be clear that this could present problems if you’re trying to parse a very big document. There are two tree parsers in PHP: - SimpleXML - DOM #### Event-Based Parsers These parsers are quicker and consume less memory than tree parsers. They work by reading the XML document node by node and providing you the opportunity to hook into events associated with this reading process. Two examples of event-based parsers are: - XMLReader - XML Expat parser The XML Expat parser is a non-validating event based parser that is also built into PHP’s core. It does not require a DTD because it does not validate XML and only requires that XML be well-formed. #### Error Codes The PHP manual[3](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-4) lists several XML error codes. This list is a subset of the 733 error codes of the underlying libxml library. Here is a partial list of XML constants that you should be familiar with because they’re more common than other codes. | Prefix Code | Description| | -------------------------- | ------------------------------------------------------------ | | XML_ERROR_SYNTAX | The XML is not well-formed.| | XML_ERROR_INVALID_TOKEN| You are using an invalid character in XML. | | XML_ERROR_UNKNOWN_ENCODING | Your XML could not be parsed because the encoding scheme couldn’t be determined. | | XML_OPTION_CASE_FOLDING| Enabled by default and sets element names to uppercase.| | XML_OPTION_SKIP_WHITE| Skips excess whitespace in the source document.| #### Character Encoding When PHP parses an XML document, it performs a process called source encoding to read the document. There are three forms of encoding that are supported: - UTF-8 - ISO-8859-1 (default) - US-ASCII UTF-8 is a multibyte encoding scheme, which means that a single character may be represented by more than one byte. The other two schemes are both single byte. PHP stores the data internally and then performs target encoding when it passes the data to functions. The target encoding is set to the same as the source encoding by default, but this can be changed. The source encoding, however, cannot be changed after the parsing object has been created. If the parser encounters a character that the source encoding cannot represent, it will return an error. If the target encoding scheme cannot contain a character, then that character will be demoted to fit the encoding scheme. In practice, thismeans that they are replaced with a question mark. #### The XML Extension The XML extension allows you to create XML parsers and define handlers. You should be familiar with the following functions. | Function| Use | | ------------------------------------------------- | ------------------------------------------------------------ | | xml:parser_create($encoding)| Creates an XML parser with the specified encoding. | | xml:parser_create_ns($encoding, $separator=":") | Creates an XML parser with the specified encoding that supports XML namespaces. | | xml:parser_free($xmlparser) | Frees up an XML parser.| | xml:set_element_handler($xmlparser, $start, $end) | This tells the parser which functions to call at the start and end of each element in the XML document. You can pass FALSE to disable a particular handler. Both $start and $end must be callable and are usually the string names of a function that exists in scope. | The function that handles the start of an element must accept three parameters: - The XML parser resource - A string that will contain the name of the element being parsed - An array of attributes that the element has The end handler function must accept two parameters: - The XML parser resource - A string that will contain the name of the element being parsed The xml:set_object($xmlparser, $object) function allows the XML parser to be used within the object. This means that you can set the methods of the object as functions for the setting the element handler. The xml:parse_into_struct($parser, $xml, $valueArr, $indexArr) function parses an XML string into two parallel array structures, one (index) containing pointers to the location of the appropriate values in the values array. These last two parameters must be passed by reference. ### DOM DOM is an acronym of Document Object Model. The DOMDocument class is useful for working with XML and HTML. It uses UTF-8 encoding and requires the libxml2 extension (Gnome XML library) and expat library. It is a tree parser and reads the entire document into memory before creating an internal tree representation. Here is a basic example of some DOMDocument syntax: load("library.xml"); // $domDoc->loadXML($xmlString); // $domDoc->loadHTMLFile("index.html"); // $domDoc->loadHTML($htmlDocumentString); $domDoc->save(); // (to a file in XML format) $xmlString = $domDoc->saveXML(); $htmlDocumentString = $domDoc->saveHTML(); $domDoc->saveHTMLFile(); // (to a file in HTML format) $xpath = new DomXpath($dom); $elements = $xpath->query("//*[@id]"); // find all elements with an id echo "I found {$result->length} elements
"; if (!is_null($elements)) { foreach ($elements as $element) { ​echo "
[". $element->nodeName. "]"; ​$nodes = $element->childNodes; ​foreach ($nodes as $node) { ​echo $node->nodeValue. "\n"; ​} } } You should be familiar with the following methods of the DOM class: | Method| Description| | --------------- | ------------------------------------------------------------ | | createElement | Creates a node element that can be appended with the appendChild method of the node class. | | createElementNS | As with createElement, but supports documents with namespaces. | | saveXML | Dumps the XML tree back into a string. | | save | Dumps the XML tree back into a file. | | createTextNode | Creates a new instance of class DOMText. | #### DOM Nodes The DOMNode class is used to work with nodes in the DOM tree. You can retrieve nodes by calling one of these methods of the DOMDocument: - ​getElementById - ​getElementsByTagName - ​getElementsByTagNameNs These methods return a DOMNodeList object, which can be traversed over using foreach(). The getElementById() function requires that you specify which attribute will be of the type id. You can do this either by including a DTD that defines it, or by calling the setIdAttribute() function. In either case, the document must be validated for the function to be called. When inserting a node as a sibling using insertBefore(), you need to reference the parent node and also specify the sibling node that you are wanting to insert the new node before. This example showsthe syntax: Silverbacks Golden Eyes XML; $domDoc = new DOMDocument(); $domDoc->loadXML($xmlString); $xpath = new DomXPath($domDoc); $team2 = $xpath->query('teams/team[2]'); $parent = $xpath->query('teams'); $textElement = $domDoc->createElement('team', 'Bearhides'); $parent->item(0)->insertBefore($textElement, $team2->item(0)); In the example, we want to insert a new team between the two existing teams. To do so, we find the team and the parent. Note These variables contain DOMElements. We cannot use the parent() method because it is defined on the DOMNode class. You should be familiar with these methods of the DOMNode class. | Method | Description| | -------------- | ------------------------------------------------------------ | | appendChild| Adds a new child node at the end of the children. | | insertBefore | Adds a new child before a reference node. | | parentNode | The parent of the node, or null if there is no parent. | | cloneNode| Clones a node and optionally all of its descendent nodes.| | setAttributeNS | Sets an attribute with namespace namespaceURI and name name to the given value. If the attribute does not exist, it will be created. | Note You need to pass a node as an argument to these functions. If you’re trying to use appendChild() then you must first use a function like DOMDocument::createElement() to create the node. ### SimpleXML SimpleXML is an extension that sacrifices robust handling of complex requirements in favor of offering a simple interface. It requires the simpleXML extension and only supports version 1.0 of the XML specifications. Caution ​ SimpleXML is a tree parser and loads the entire document into memory when parsing it. This may make it unsuitable for very large documents. SimpleXML offers an object-oriented approach to accessing XML data. All the objects that it makes are instances of the SimpleXMLElement class. Elements become properties of these objects and attributes can be accessed as associative arrays. #### Creating SimpleXML Objects You can create SimpleXML objects using procedural methods, or through an object-oriented approach: 'name', 'password'=>'secret'); // call the login method directly $client->login($params); // If you want to call __soapCall, you must wrap the arguments in another array as follows: $client->__soapCall('login', array($params)); In the previous example, we connect to an example WSDL and call the login method using two different methods. Note that using the SoapClient::__soapCall() method requires you to wrap the parameters in an array. It is not compulsory for a SOAP service to provide a WSDL. If you need to use such a service you may pass null as the WSDL file but then need to provide information about the service endpoint. You must provide the location and URI options and may optionally provide other information about the version of the SOAP service, as in this example: 'http://example.com/soap.php', ​'uri' => 'http://test-uri/', ​'style' => SOAP_DOCUMENT, ​'use' => SOAP_LITERAL)); ]); When you construct the SoapClient class, you can set the trace parameter to true to enable debugging the raw SOAP envelope headers and body. The following two debugging commands require that the trace be true and allow you to inspect details of the request: - ​ SoapClient::__getLastRequestHeaders() - ​ SoapClient::__getLastRequest() ### Offering a SOAP Service The SoapServer class provides a SOAP server. It supports versions 1.1 and 1.2 and can be used with or without a WSDL service description. Here is an example of setting up a SOAP server: 'http://localhost/test']; $server = new SoapServer(NULL, $options); $server->setClass('MySoapServer'); $server->handle(); We can see that we first create the server with an array of options. In thisexample, we are not supplying a WSDL in the first parameter and so we must supply the URI of the server namespace in the options array. Once we have an instance of the SoapServer class, we pass in the name of the class that it will use to serve requests. The methods in the class will be callable by a SOAP client connecting to the server. Instead of setting a class you may also use a concrete object to handle SOAP requests by passing it as a parameter with the SoapServer::setObject() function. ## REST Web Services REST isan acronym for Representational State Transfer and is an architectural style rather than a PHP extension or set of commands. REST has several constraints that are intended to improve performance and maintainability of web services. Tip Compare “Service Oriented Architecture,” which is typically implemented in SOAP to “Microservice Architecture,” which is more often implemented in REST. REST has several verbs that are similar to HTTP request types. This leads to some confusion, but it is important to note that REST does not have to use HTTP as a transport layer to communicate. HTTP just happens to be very convenient for REST because it is stateless and the request typestranslate well into REST verbs. REST exposes Uniform Resource Identifiers (URI) that are linked to resources. These links are called REST endpoints. Depending on the HTTP type used to access them, they will perform an action on the resource (change its state). The HTTP type is used to signal the REST verb to be performed. REST focuses on resources and providing access to those resources. A resource could be something like a “user”. Much like a database schema represents the user entity, REST will represent the user in a JSON or XML structure. A representation should be readable by both the server and the client. REST can be used to transfer JSON, XML, or both. We’ll look at this in a bit more detail later. In PHP, one of the most common uses for REST APIs is to provide servicesfor an AJAX enabled frontend, such as one written in Angular or ReactJS. ### Application and Resource States A REST server should not remember the state of the application and the client should send all the information necessary for execution. This means that every request to a server is self-contained. If a request to a server failed it will not affect the success or failure of other requests. This improves the reliability of the application. The server is not responsible for remembering what state the application is in and relies on the client to send all the information it needs to process the request. This means that the client stores and maintains the application state (and not the server). Application statelessness has important implications for scaling horizontally. Because no individual server is maintaining state, a request can reach any server in a group and be handled correctly. The resource that REST is providing access to has state that is expected to persist between requests. Resource state is maintained on the server. ### REST Verbs REST has several verbs that are used to alter the state of a resource on the server. Verbs operate either on a single resource or a collection of resources. | Resource| GET | PUT | POST | DELETE | | ------------- | ------------------------------------------------- | ----------------------------------------------------- | ------------------------------------ | ----------------------------- | | Collection| Lists the URIs where you can retrieve the members | Replace the collection with another collection | Create a new entry in the collection | Deletes the entire collection | | Single Entity | Retrieve a representation of the single element | Replace the element, or create it if it doesn’t exist | Creates a new member | Deletes the member | ​PUT and POST look similar, but have an important distinction. POST requires you to specify all the required attributes for an element and will create a fresh element. PUT will replace the attributes you specify for an existing record and you don’t need to supply all the attributes unless you’re creating a new record. To explain with an example, let’s consider a user who has a name and a title. First, we POST to create a new user with a name “Alice” and the title “Mrs”. Then Alice graduates and becomes a doctor, so we PUT to her record and include just the title as “Dr”. We don’t have to specify her name and, because we don’t, her name will not be changed. ### HATEOAS HATEOAS stands for “Hypertext As The Engine Of State”. In this concept, the response from the server will include information about what actions the client can take next. These options will be marked up in hypertext. The aim is for the client not to require prior knowledge of the endpoints of the REST service. Rather, they will be provided with the endpoints they need to proceed through the application when they make a query. Let's consider an example: GET /account/12345 HTTP/1.1 HTTP/1.1 200 OK

<account_number>12345</account_number>

100.00

In the previous example, from the Wikipedia page on HATEOAS,[7](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-8) we are retrieving information about a bank account. The server responds with a list of URIs that can be used for further actions. If the account had a negative balance, for example, the server may not include the link to withdraw money. The server is guiding the client through the API by exposing additional URIs that are relevant to the last operation.

Request Headers

HTTP allows passing headers in its request. REST clients will use these to indicate to the server what they are providing and what they are expecting back.

A REST client should use the accept header to indicate to the server what sort of content (representation) it wants back. For example, if a client sets the accept header to text/xml, it is telling the server that it wants an XML-formatted response.

The client will also set a Content-Type header to inform the server of the MIME type of its payload. See the section in the response header for more detail.

Response Headers and Codes

The Content-Type header is sent by the server and defines the MIME type of the body that is being sent. For example, a server may set the content-type to application/json to indicate that the body of the response contains JSON formatted text.

The server will also set a status code that informs the client of the result of the request. Some of the common codes are listed here, but there are many more.[8](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-9)

Code Meaning
200 The request processed successfully
201 The resource was created
202 The resource was accepted for processing, but has not yet been processed
400 Bad request (client error)
401 Unauthorized; the client must authenticate itself before accessing this resource
403 Forbidden; the client has authenticated itself but does not have permission to access this resource
500 Server or application error

Tip

It is very poor practice to send a message in the response body that contradicts the HTTP response code.

Within the Zend framework the term “context switching” refers to changing the output of your program depending on whether it is responding to a REST request or some other request.

For example, you may respond with an HTML page for normal requests or respond with JSON if the request originated via XMLHttpRequest (AJAX).

You could also respond with XML or JSON, depending on what content type the client indicates it wants as a response.

Another example could be to respond with different layouts, depending on what sort of browser is being used (mobile device versus desktop for example).

You should be familiar with the concept of the server responding differently to a call to the same URL, depending on how the client sets up its request.

Sending Requests

The curl extension is a common way to send REST requests in PHP. Curl lets you specify headers and request types.

There are libraries that wrap the curl functions. One of the popular ones is Guzzle,[9](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-10) which is easy to install and use. It offers a very wide range of features and, at the time of writing, is in my opinion the best choice of request client for PHP.

JSON

JSON is an acronym of JavaScript Object Notation. In PHP, it is used a lot with Ajax, which is an acronym for Asynchronous JavaScript and XML.

JSON lets you serialize an object as a string so that it can be transported between services. Ajax is a means to transport the string.

Together these technologies allow you to communicate between JavaScript applications in the browser and PHP applications on the server.

The JSON extension is loaded in PHP by default and provides methods to handle converting to and from JSON.

It provides a number of constants, including:

Constant Meaning
JSON_ERROR_NONE Confirms whether a JSON error occurred or not.
JSON_ERROR_SYNTAX Confirms if there was a syntax error parsing JSON and helps detect encoding errors.
JSON_FORCE_OBJECT If an empty PHP array is encoded, this option will force it to be encoded as an object.

There are three functions provided by the extension.

​ json_decode() takes a string as its first argument and returns an object. If the second parameter is set true, it will return an associative array.

From PHP 5.3 onward, two additional options are supplied—$depth and $options. Depth refers to the recursion depth and currently the only option is JSON_BIGINT_AS_STRING, which changes casting large integers as floats to be cast as strings.

If the recursion depth is exceeded, json_decode() will return NULL and json_last_error_msg() will return "Maximum stack depth exceeded". This will happen if the array has more levels than the depth you have specified as acceptable.

As an example, consider this code:

[ ​"apple" => ["taste" => "sweet", "color" => "yellow"], ​"banana" => ["taste" => "sour", "color" => "green"], ​"cherry" => ["taste" => "sweet", "color" => "red"] ], "vegetables" => "yuck" ]; $str = json_encode($arr); $decode = json_decode($str, true, 1); echo json_last_error_msg(); // Maximum stack depth exceeded The array has two levels because each of the fruits contains an array. We specify that we want to decode only one level of depth and so $decode will be NULL and the script will output "Maximum stack depth exceeded". ​ json_encode() takes a variable of any type (other than a resource) as a parameter and returns the JSON representation. It has two optional parameters—$depth and $options—which are the same as described previously. ​ json_last_error() returns the last error code that occurred in either of the previous functions and json_last_error_msg() returns a string message. Tip Remember from Chapter [6](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-11) that JSON is the preferred way to serialize data that is transported to the client. ## Date and Time PHP supplies several functions that retrieve the date and time from the server. You should set a default time zone in your configuration or set it at runtime in your script. You should set the time zone to match the time zone that your server is in, so that PHP can correctly interpret the server time. This also lets your script be aware of adjustments like daylight savings time. PHP 5.2 introduced the DateTime class, which deals with a wide range of date and time calculations. It is recommended to use this class instead of working with the functionslike date() and time(). To create a new DateTime object, you pass it a string that it can parse. It understands a wide range of string formats, such as shown in this example: ```php format(DateTime::COOKIE) . PHP_EOL; } ``` All the strings in the array from this example will be understood. If a date format is ambiguous, then you can use the DateTime::createFromFormat() command to create the object. For example, the date 3 June 2013 will be written as 06-03-2013 by an American, while the rest of the world would write it as 03-06-2013. If you gave either of these strings to PHP, it would not know whether you mean 3 June 2013 or 6 March 2013. To resolve the ambiguity, you can specify which format you’re using in your string, like this: format(DateTime::COOKIE); This script will output something like Wednesday, 06-Mar-2013 12:56:42 CET. Note that if you omit the time when creating a DateTime class, the time that the script is running at will be used. ### Formatting Dates In these examples, we’ve used one of the class constants provided by DateTime to format our date. The manual has a list of these constants, which are common use-cases for date display or storage. They appear in this table: | Constant | Format | | -------- | ---------------- | | ATOM | Y-m-dTH:i:sP | | COOKIE | l, d-M-Y H:i:s T | | ISO8601 | Y-m-dTH:i:sO | | RFC822 | D, d M y H:i:s O | | RFC850 | l, d-M-y H:i:s T | | RFC1036 | D, d M y H:i:s O | | RFC1123 | D, d M Y H:i:s O | | RFC2822 | D, d M Y H:i:s O | | RFC3339 | Y-m-dTH:i:sP | | RSS| D, d M Y H:i:s O | | W3C| Y-m-dTH:i:sP | These are string constants and contain date and time formatting codes. The formatting codes are replaced with a value by the DateTime class. For example, the symbol “Y” is replaced with the four-digit year of the date being stored. Obviously, the point of declaring the constant is so that you don’t have to memorize the strings, so don’t worry about studying the formats. I included the formatting strings because they are a good indication of the commonly used ones. Date and time formatting codes are case-sensitive. For example, “y” is a two-digit year and “Y” is a four-digit year. Characters in the formatting string that are not recognized as formatting characters will be placed into the output unchanged. So, the string “Y-m-d” would include the hyphens between the year, month, and day when output—like this “2015-12-25”. You can find a list of the PHP date and time formatting codes on the manual page,[10](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-12) but here are the ones that are in the previous table: | Code | Replaced With | Example(s) | | ---- | ------------------------------------------------------------ | -------------- | | Y| A full four-digit year | 1999 | | M| Two-digit month, with leading zeroes | 06 | | d| Day of the month, two digits with leading zeros| 14 | | D| A three letter textual day | Mon, Tue, Wed | | H| 24-hour format hour with leading zero | 00, 09, 12, 23 | | i| Two-digit minute, with leading zeroes| 05,15,25,45| | s| Two-digit seconds, with leading zeroes | 05,15,25,45| | P| Difference to Greenwich time (GMT) with colon between hours and minutes (PHP 5.1.3+) | +02:00 | | O| Difference to Greenwich time (GMT) in hours| +0200| | T| Time zone abbreviation | EST, CET | ### Date Calculations The most simple calculations can be performed using the DateTime class method modify(). For example, to find the date and time that is one month in the future, you can do the following: modify('+1 month'); echo $dateTime->format(DateTime::COOKIE) . PHP_EOL; PHP offers a much more flexible way to work with date calculations, however. The DateInterval class is used to store either a fixed amount of time (in years, months, days, hours, etc.) or a relative time string in the format that DateTime’s constructor supports. The DateTime class allows you to add() or sub() a DateInterval from a DateTime. It will handle leap years and other time adjustments while doing so. To specify a fixed amount of time when creating a DateInterval object, we pass its constructor a string. The string always starts with P and then lists the number of each individual date unit in descending order. Optionally, the letter T appears and then the time units are included. This makes a lot more sense with some examples: | String | Description| | ------------ | ------------------------------------------------------------ | | P14D | 14 days| | P2W| Two weeks| | P2W5D | This is invalid; you may not specify weeks and days together in one string; the weeks will be ignored | | P2WT5H | Two weeks and five hours | | P1Y2M3DT4H5M | One year, two months, three days, four hours, five minutes | Note that: - Every string begins with P - The number of units precedes the letter indicating the unit - Time units are split from the date units by the letter T - Units are sorted in descending order Here is an example in code: ```php ``` add($dateInterval); echo $dateTime->format(DateTime::COOKIE) . PHP_EOL; ``` ``` Thiscode outputs the date and time that is one month, two days, three hours, four minutes, and five seconds after 1st December 13:14:15. ### Manual Date Calculations Occasionally, you will need to work with a UNIX style timestamp. This timestamp is a number that holds the number of seconds that have passed since the UNIX epoch, 1 January 1970. One advantage of the timestamp is that it isagnostic of time zones. There are several PHP functions that let you create a timestamp. The strtotime() function is a very flexible way to convert a date-time description into a timestamp. It is intelligent enough to recognize phrases like “next Monday” or “+1 year”, as well as more mundane strings like “1 April 2017”. The mktime() function accepts a parameter for each of hour, minute, second, month, day, or year. mktime() returns the UNIX timestamp of the arguments given. If the arguments are invalid, the function returns FALSE. Note that the order of the parameters does not increase in unit size, but is in the order “h i s m d y”. You can leave out parameters right to left in which case they will default to the current date value. So if the current year is 2016 and you call mktime() without specifying the year, PHP will assume that you mean 2016. If you pass a parameter to mktime() that is greater than the value that should be allowed, mktime() assumes that you mean that you’re referencing the next period. For example, there are 31 days in December. If you call mktime(0, 0, 0, 12, 32, 2016) then you will be given a timestamp for the first day in the next month; in other words, for 1 January 2017. ### Comparing Dates The DateTime::diff() method allows you to compare the difference between two DateTime objects. It returns a DateInterval that contains the period of time between the two dates being represented. Note that the DateTime class handles time zone and daylight savings time conversions for you. Let's try to find out how long it is to Christmas. ```php $christmas) { $christmas = new DateTime('25 december next year'); } $interval = $christmas->diff($now); // 97 days until Christmas echo $interval->days . ' days until Christmas' . PHP_EOL; ``` Notice the following in this snippet: - Passing no parameter to the construct uses the current date and time. - We can use mathematical operators like >, <, and == to compare DateTime objects. - We can use fairly flexible language when creating a DateTime, such as “25 december next year” for the case where the current date is between Christmas and New Year. - The diff() method returns a DateInterval. - ​ TheDateInterval object has a number of public properties that can be accessed to measure years, months, and in this case days. ## PHP SPL Data Structures The standard PHP library (SPL) is a collection of interfaces and classesthat are meant to solve common problems. It includes several classesthat help you work with standard data structures. ### Interfaces Related to Data Structures Before we look at the SPL data structure classes, it is worth looking at some of the interfaces that they implement. This makes it considerably easier to remember what functions the classes have. #### Iterator The Iterator interface extends the Traversable interface. The Iterator interface[11](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-13) defines five methods that are used to move through the collection. | Method | Purpose | | ------- | ----------------------------------------- | | current | Returns the current element | | key | Returns the key of the current element| | next| Moves forward to next element | | rewind | Rewinds the iterator to the first element | | valid | Checks if current position is valid | #### Traversable A class that implements the traversable interface[12](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-14) can be looped over using foreach(). This interface cannot be implemented by itself, it can only be implemented by implementing an interface that tells the class how to iterate over the collection. In practical terms, this means that to implement the traversable interface, you must implement either the Iterator or IteratorAggregate interface. #### ArrayAccess This interface provides the ability to access objects as arrays. To do so, you need to implement four methods: | Method | Purpose| | ------------ | -------------------------------------- | | offsetExists | Whether an offset exists | | offsetGet| Offset to retrieve | | offsetSet| Assign a value to the specified offset | | offsetUnset | Unset an offset | If your class implements this interface, then you will be able to use array syntax when referencing an object instantiated from it. #### Countable If your class implements the Countable interface, you will be able to use the count() function to find how many elements it has. The Countable interface has an abstract method called count. This method will be called when you call the PHP function count() on an object instantiated from a class that implements the interface. push(5);| 5| | // this uses array syntax to add a new element| | | $stack[] = 4; | 5, 4 | | // now we push another number to the end of queue | | | $stack->push(3);| 5, 4, 3 | | // this inserts the number 100 into position 1| | | // elements below it are shuffled down | | | $stack->add(1, 100); | 5, 100, 4, 3 | | // this returns the last value in the queue | | | echo "Pop: " . $stack->pop() . PHP_EOL; | 0, 100, 4| | foreach ($stack as $key => $value) {| | | echo "$key => $value" . PHP_EOL;| | | } | | The output of this code is as follows: Pop: 3 2 => 4 1 => 100 0 => 5 Note The keys are contained in the stack in descending order (2,1,0). ### Heaps Heaps are tree-like structures where parent nodes can have zero, one, or more child nodes. Heaps define a comparison rule that allows you to determine whether one node is greater or less than another node. In a heap, a parent node will always be equal to or greater than itschildren. The comparison function is used to determine whether a node is greater than or less than another. Note The SplHeap class is an abstract class. When you use it, you need to implement the compare function. The SplHeap class implements the Iterator[17](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-19) interface, which means that you can use foreach() to move through it. The SplMaxHeap class extends from SplHeap and keeps the maximum value at the top. It does this by implementing the compare() function for you. Similarly, the SplMinHeap class keeps the minimum value at the top. Note ​ SplMinHeap and SplMaxHeap are just classes that extend SplHeap and implement the compare() to provide directional sorting. Let's look at an example of a straight-forward heap: $b; } } $heapExample = new MyHeap; $heapExample->insert(10); $heapExample->insert(5); $heapExample->insert(15); while ($heapExample->valid()) { echo $heapExample->current() . PHP_EOL; $heapExample->next(); } This code outputs the numbers in sorted descending order, because when we insert them, it applies the compare() function to determine where to place them. Note If we were to amend the code and extend SplMinHeap or SplMaxHeap instead of SplHeap, the output is the same as the previous code! I can hear you saying with annoyance that SplMinHeap is supposed to keep the lowest value on top, so why is the output showing that 15 is still on top? The answer is because all that the SplMinHeap and SplMaxHeap classes provide is a default implementation of the compare() function, which we are overriding in the class definition. You can extend SplMinHeap but as long as your compare() function remains the same, as in the previous example, you will alwayshave a max heap. To get a working implementation of a min heap (in our example), you need to either swap the operands for the spaceship operator or avoid implementing the compare() function entirely and use the one declared in SplMinHeap. ### Arrays The SplFixedArray[18](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-20) structure stores data in a continuous manner, accessible by indexes. It is faster than normal PHP arrays, but is also less flexible because it is of fixed length and can only use integers as indexes. The SplFixedArray class implements the Iterator interface and the ArrayAccess interface. ### Maps A map is a structure that holds key-value pairs. A PHP array is a sort of map because it stores values against integer (or string) keys. The SplObjectStorage provides a map from objects to data, or if you ignore data, it can function as an object set. ​SplObjectStorage is not an abstract class and can be instantiated directly. It implements the Countable, Iterator, Serializable, and ArrayAccess interfaces. Because it implements the ArrayAccess interface, you can use array syntax to reference the data of objects inside the structure, like this: 'passwords.xslx', 'size' => '102400']; $bucket[$file] = $metaData; In the example, we are mapping data (the metadata) against a specific instance of an object (the file). ### Summary of SPL Data Structures | [ SplHeap ](http://php.net/manual/en/class.splheap.php) | A heap is a tree collection where the children of a parent must alwayshave a value lower than their parent. There are different types of heap. | | ------------------------------------------------------------ | ------------------------------------------------------------ | | [ SplMaxHeap ](http://php.net/manual/en/class.splmaxheap.php) | This is a type of heap where the maximum is kept at the top of the heap. | | SplMinHeap | In this type of heap, the minimum is kept at the top. | | SplPriorityQueue | This is a queue where each element also has a "priority" associated with it. An example of a use-case is bandwidth management wherein traffic of a certain type has a higher precedence over other traffic. | | SplFixedArray | This is a faster implementation of an array, but it limits you to using an array of fixed length that only contains integers. | | SplObjectStorage | This class provides a convenient way to map objects and their data. | There is also an extension called DS that provides alternative data structures. You can find its documentation on the PHP web site[19](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-21) and its source code on GitHub. You won't need to know about it for your Zend exam. Chapter [7](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-0) Quiz Q1: True or false? Characters that cannot be encoded in the target XML encoding scheme generate an error. | True | | ------------------------------------------------------------ | | False; they generate a warning | | False; they are fitted into the encoding scheme (converted to question marks) | | None of the above | Q2: True or false? It is not possible for a server to send a REST response with HTTP status code 200 if the request failed. | True | | ----- | | False | Q3: What will this code output? [ "apple" => ["taste" => "sweet", "color" => "yellow"], "banana" => ["taste" => "sour", "color" => "green"], "cherry" => ["taste" => "sweet", "color" => "red"] ], "vegetables" => "yuck" ]; $str = json_encode($arr); $decode = json_decode($str, true, 1); echo json_last_error_msg(); | Syntax error; it will not run| | ------------------------------------------------------------ | | Nothing; there is no error msg so the echo statement outputs nothing | | Maximum stack depth exceeded | | Fatal error, the second parameter to json_decode cannot be "true" | Q4: You should set the default time zone for your PHP application. Which of the following methods can you use to do so? Choose as many as apply. | Using the function set_date_default_timezone() | | ------------------------------------------------------------ | | Editing php.ini| | Using the Linux time() command on PHP | | Using the PHP ini_set() function, like this:ini_set('date.timezone', 'Europe/Edinburgh'); | Q5: What will this code output? push(5); $stack[1] = 4; echo $stack->pop(); | 4 | | ------------------------ | | 5 | | A fatal error will occur | Q6: What is wrong with the following PHP code? 'name', 'password'=>'secret'); // call the login method directly $client->login($params); | Syntax error; it won’t run at all| | ------------------------------------------------------------ | | The parameters to the login method need to be passed like this: $client->login([$params]); | | You can't call a method on the SoapClient directly | | Nothing is wrong; this will work | Q7: What will this code output? Silverbacks Golden Eyes XML; $xml = new SimpleXMLElement($xmlString); $result = $xml->xpath('teams/team[1]'); echo $result[0]; | Syntax error; it won’t run | | ------------------------------------------------------------ | | Silverbacks| | Golden Eyes| | It will generate a warning because the xpath will fail to evaluate | Q8: You can convert a SimpleXML object to DOM with the ______ function. | dom_import_simplexml()| | ----------------------- | | simple_xml:import_dom() | | simple_xml:export_dom() | | None of the above | Q9: What is the output of this script? Silverbacks Golden Eyes XML; $domDoc = new DOMDocument(); $domDoc->loadXML($xmlString); $textElement = $domDoc->createElement('team', 'Bearhides'); $result = $domDoc->xpath('teams/team[2]'); $result[1]->insertBefore($textElement); echo $domDoc->saveXML(); | This will produce a fatal error | | ------------------------------------------------------------ | | An XML document with a new team at the beginning of the list of teams | | An XML document with a new team between the two teams| | None of the above | Q10: What will the following code output? add($interval); echo $dateTime->format(DateTime::COOKIE); | This will produce a fatal error | | ------------------------------------------------------------ | | A date one year, two months, three days, four hours, and five minutes in the future | | None of the above | Footnotes [1](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-22) ​ [ https://en.wikipedia.org/wiki/Well-formed_document ](https://en.wikipedia.org/wiki/Well-formed_document) [2](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-23) ​[ https://php.net/manual/en/xsltprocessor.transformtoxml.php ](https://php.net/manual/en/xsltprocessor.transformtoxml.php) [3](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-24) ​ [ https://php.net/manual/en/xml.error-codes.php ](https://php.net/manual/en/xml.error-codes.php) [4](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-25) ​ [ https://en.wikipedia.org/wiki/XPath ](https://en.wikipedia.org/wiki/XPath) [5](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-26) ​ [ https://www.w3schools.com/xml/xml:xpath.asp ](https://www.w3schools.com/xml/xml:xpath.asp) [6](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-27) ​ [ https://en.wikipedia.org/wiki/SOAP ](https://en.wikipedia.org/wiki/SOAP) [7](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-28) ​[ Https://en.wikipedia.org/wiki/HATEOAs ](https://en.wikipedia.org/wiki/HATEOAS) [8](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-29) ​[ https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html ](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) [9](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-30) ​[ http://docs.guzzlephp.org/en/stable/ ](http://docs.guzzlephp.org/en/stable/) [10](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-31) ​[ https://php.net/manual/en/function.date.php ](https://php.net/manual/en/function.date.php) [11](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-32) ​ [ https://php.net/manual/en/class.iterator.php ](https://php.net/manual/en/class.iterator.php) [12](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-33) ​ [ https://php.net/manual/en/class.traversable.php ](https://php.net/manual/en/class.traversable.php) [13](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-34) ​[ https://php.net/manual/en/class.spldoublylinkedlist.php ](https://php.net/manual/en/class.spldoublylinkedlist.php) [14](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-35) ​[ https://php.net/manual/en/class.splstack.php ](https://php.net/manual/en/class.splstack.php) [15](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-36) ​[ https://php.net/manual/en/spldoublylinkedlist.setiteratormode.php ](https://php.net/manual/en/spldoublylinkedlist.setiteratormode.php) [16](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-37) ​[ https://php.net/manual/en/class.splqueue.php ](https://php.net/manual/en/class.splqueue.php) [17](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-38) ​[ https://php.net/manual/en/class.iterator.php ](https://php.net/manual/en/class.iterator.php) [18](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-39) ​[ https://php.net/manual/en/class.splfixedarray.php ](https://php.net/manual/en/class.splfixedarray.php) [19](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-40) ​[ https://docs.php.net/manual/en/book.ds.php ](https://docs.php.net/manual/en/book.ds.php) © Andrew Beak 2017 Andrew BeakPHP 7 Zend Certification Study Guide[https://doi.org/10.1007/978-1-4842-3246-0_8](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-169) # 8. Input-Output Andrew Beak1 (1) Grafham, Cambridgeshire, UK In this chapter, we’re going to be looking at how PHP managesinput-output. We’ll be examining how we can read from or write to the file system as well as the network. ## Files There are two main groups of functions to deal with files: those that work with file resources, and those that work with a filename. Remember that a resource is a type of variable that can’t be stored directly in PHP. A file resource is an operating system file handle. All the functions that deal with file resources begin with a single f letter and then have a verb describing their function. For example, fopen() opens a file resource. Functions that work with the string name of a file all start with the word file and are followed by a verb descriptive of what they do. For example, file_get_contents() takes a string filename and returns the contents of that file. ### Opening Files The function fopen() is used to open files. It returns a resource variable that is a handle to the file. You must pass two parameters to fopen(): - The name of the file in your file system - The file mode that you want to open it with ### File Modes Files can be opened in different modes. File modes describe how we will be interacting with the file. File modes relate to operating system file privileges. For example, if the PHP user only has read access to a file then an attempt to open it in write mode will be denied by the operating system. If we try with a lesser privilege (such as read only), then the operating system will create a file handle for us. We communicate two pieces of information about how we intend to use a file when we specify a mode: - Whether we are reading, writing, or both - Whether we want to place the file pointer at the beginning or ending of the file The file pointer is like an iterator cursor. It stores the file position that will be returned on the next read. The following table summarizes the common file modes. | Mode | Read/Write | Pointer | Behavior | | ---- | ---------- | ------- | ------------------------------------------------------------ | | r| R| Start || | r+ | RW | Start || | w| W| Start | Truncates an existing file or creates a new file if it doesn’t exist | | w+ | RW | Start || | a| W| Start | Creates a new file if it doesn’t exist and preserves the current file if it does | | a+ | RW | Start || | x| W| N/A | Tries to create a new file for write; returns FALSE if the file already exists and generates E_WARNING | | x+ | RW | || | c| W| Start | Tries to create the file if it doesn’t exist; if it does exist, places the cursor at the front of the file | | c+ | RW | || You’ll notice that adding a + symbol to a file mode has the effect of indicating that you also want to perform the opposite of the default mode. So, when we’re overwriting a file, if we add a + symbol then we indicate that we also want to read the file. The behavior remains the same, however, and so I’ve omitted it from the table to keep it easier to read. When using the w modes to overwrite a file, PHP will truncate the file to zero bytes. This is useful if you want to have a file that is overwritten with new data. The x modes will return FALSE and generate a warning if the file already exists. This is useful if you want to avoid overwriting data that you want to keep. The c mode will create a file if it exists or open an existing file. The pointer will be set to the start of the file for existing files. ### File Mode Flags There are two flags that you can specify by adding them to the end of the mode string. The default flag is defined by your SAPI and the version of PHP that you’re using, so for compatibility purposes you should specify them. You can specify a b flag to specify that you’re working with binary files. This means that no characters will be translated. This is necessary when you’re working with images or other binary files. On a Windows server, you can specify a t flag to translate \n to \r\n. Tip To keep your code portable, you should use the b flag and make sure that your code uses the correct line endings. ### Reading Files You can read from a file resource using the fread() function. file($filename); ### Managing Files You can use PHP to manage files. Some of the common functions are listed in this table. | Function | Purpose| | -------- | ------------------------------------------------------------ | | copy | Copies a file. | | unlink | Deletes a file.| | rename | Renames a file. You can use this to move a file between directories. | | chmod| Sets file permissions. | | chgrp| Changes the group of the file. | | chown| Changes the owner of the file (superuser only).| | umask| Changes the current umask. | ### Determining the Type of a File System Object It is good programming practice to verify that files and directories exist and that you have the proper permissions to use them in the way you intend. PHP provides functions that return Boolean values if the object matching the string you pass as the parameter meets the test. These functions take a string parameter that is the name of a file or directory. In the following table, the check is against an object found that matches the name given in the parameter. | Function | Checks | | ---------------- | -------------------------------------------- | | is_dir | Is a directory | | is_file| Is a file | | is_readable| Is a file or directory and can be read | | is_writeable | Is a file or directory and can be written to | | is_executable| Is a file or directory and can be executed | | is_link| Is a symlink | | is_uploaded_file | Was uploaded by a POST request | All the functions will return FALSE if no file system object was found that matched the name given in the parameter. ### Magic File Constants PHP has several magic constants that you can use in relation to the file currently executing. | Constant | Refers To| | ------------ | ---------------------------------------- | | __LINE__ | The line of the file currently executing | | __FILE__ | The full path and filename of the file | | __FUNCTION__ | The current function name | | __CLASS__| The name of the class in scope | | __METHOD__ | The name of the method being executed| These constants are very useful when writing debug logs. For example, I typically start all of my log messages with the __METHOD__ tag so that it’s immediately clear which class and method the log message is generated in. ## Streams Streams in PHP are a way of generalizing file, network, data compression, and other operations that share a set of common functions and uses. A stream is almost like a conveyer belt of things that come to you one by one. In PHP, you can also skip along the conveyer belt and seek to a position instead of waiting for it to come to you. Streams are referenced in a format that you might recognize: scheme://target For example, [ http://www.php.net ](http://www.php.net) specifies the http scheme and the target as the URL of the PHP web site. ### Stream Wrappers Wrappers are code objects that translate the stream into a particular encoding or protocol. The PHP manual[3](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-172) has a list of the wrappers that are implemented within the language, and the stream_wrapper_register() function lets you define your own. | Protocol | Use | | ---------------- | --------------------------------- | | file://| Accessing the local file system | | http://| Accessing HTTP(s) URLs| | ftp:// | Accessing FTP(s) URLs | | php:// | Accessing various I/O streams | | compress.zlib:// | Compression streams | | data://| Data (RFC 2397) | | glob://| Find pathnames matching a pattern | | phar://| PHP archive | | ssh2://| Secure Shell 2 | | rar:// | RAR | | ogg:// | Audio streams | | expect://| Process interaction streams | The PHP streams that you can access are stdin, stdout, stderr, input, output, fd, memory, temp, and filter. Note that in order to improve readability, I’ve omitted the protocol for all of these streams. When you use them, they should all be prefixed by the php:// protocol, for example, stdin is php://stdin. As an example of reading a stream, let’s look at how to read the body of a PUT request. At some time in your career you will be coding a REST API and will need to read and parse the body of PUT requests that clients are making to your server. There is no superglobal for this request type as there is for GET and POST, so how is it done? The answer is in the php://input stream! 1024) { ​die("Download too big!"); ​} } } $context = stream_context_create(); stream_context_set_params($context, ["notification" => "callback"]); $handle = fopen('http://www.example.com', 'r', false, $context); fpassthru($handle); You can change the options and parameters with the stream_context_set_params() function, while the stream_context_get_params() will return the current parameters for the stream. Chapter [8](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-169) Quiz Q1: Assume that the web server user owns the data.csv file and that it contains the string "Hello World" before this script runs. What will the output of this code be? file('earth.jpeg') . PHP_EOL; | This produces an error | | ------------------------------------ | | GIF image data, version 89a, 400x400 | | JPEG image data, 400x400 | | image/gif| | image/jpeg | | Could not rename the file | | None of the above | Footnotes [1](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-173) ​[ https://en.wikipedia.org/wiki/File_(command ](https://en.wikipedia.org/wiki/File_(command)) [2](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-174) ​[ https://php.net/manual/en/function.finfo-file.php ](https://php.net/manual/en/function.finfo-file.php) [3](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-175) ​[ https://php.net/manual/en/wrappers.php ](https://php.net/manual/en/wrappers.php) © Andrew Beak 2017 Andrew BeakPHP 7 Zend Certification Study Guide[https://doi.org/10.1007/978-1-4842-3246-0_9](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-101) # 9. Web Features Andrew Beak1 (1) Grafham, Cambridgeshire, UK PHP is a language created for the web. Its original purpose was to make it easier to make web pages and it remains heavily focused on server-side scripting. This chapter looks at some of the language features that make it one of the world's most popular server-side web programming languages. ## Request Types HTTP has several different request methods[1](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-102) that are commonly referred to as HTTP verbs. The HTTP specification[2](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-103) lays out in considerable detail what each verb is intended for. Your application should adhere to this specification so that it is compatible with the clients using it. | Verb| Used To| | ------- | ------------------------------------------------------------ | | GET | Retrieve a representation of the specified resource| | HEAD| Identical to GET but without any response body | | POST| Submit an entry to the server, often resulting in a change such as adding a new resource | | PUT | Replace the specified resource with the one in the request payload | | PATCH | Apply a partial modification to the specified resource | | DELETE | Delete the specified resource| | CONNECT | Initiate an HTTP tunnel[3](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-104) | | OPTIONS | Describe the communication options for the target resource | | TRACE | Performs a message loop-back test to the target resource | ## Request Data In a typical production web environment, PHP accepts requests passed to it by the web server. It runs and processes the request before terminating and waiting for the next request. The web server can pass data along with the request and this data forms part of the context[4](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-105) in which PHP runs. An HTTP request consists of three parts: the URL, the headers, and the body. Data can be included in any of these parts of the request and will be made available to your PHP application as follows: | Source | Passed In | Available In| | ------------- | ----------------------------- | --------------------- | | GET | Parameters in the request URL | $_GET | | POST| Body of the request | $_POST | | PUT | Body of the request | Read with php://input | | PATCH | Body of the request | Read with php://input | | Cookie | The “cookie” header | $_COOKIE| | Uploaded file | Body of the request | $_FILES | If PHP is processing a request from the command line, then $_SERVER['argv'] contains an array of the arguments passed and $_SERVER['argc'] contains the number of arguments that were passed. In addition to data contained in the HTTP request, PHP can accept data from the environment in which it runs. For example, you could run PHP in a docker container and set an environment variable that contains the address of the database server. You’d be able to reference this in your PHP script using the $_ENV superglobal.[5](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-106) ### The Request Superglobal The $_REQUEST superglobal is an associative array that by default contains the contents of $_GET, $_POST, and $_COOKIE. The php.ini setting variables_order determines which of the ENV, GET, POST, and COOKIE variables are present in the $_REQUEST array as well as the order.[6](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-107) If the same variable is in multiple request types, it will take on the value of the last one in the sequence of this settings value. So, for example, imagine the configuration is set to EGPCS, indicating that POST comes after GET. Then if both $_GET['action'] and $_POST['action'] are set, then $_REQUEST['action'] will contain the value of $_POST['action']. Because you won’t be certain of exactly where the data in $_REQUEST is coming from, you should use this array with caution. Introducing uncertainty in your code complicates your testing and could impact security. ### POST By convention, POST requests are used to send data to the web site and instruct it to create a new entity. It is a write operation in the CRUD paradigm. #### Receiving POST Data Variables sent in a POST request are included in the body. Contrast this with GET requests that pass variables in the URL. If a user submits a form, then the browser will encode the values into the body of the request and send it to you. Similarly, an application POSTing to an API endpoint will need to encode the variables into the request body. PHP will make them available to you in the $_POST variable. For example, here is an example of a POST to a web site that is sending Ronald as the value of the name variable. This request would be used to add a person called Ron to the fan club . POST HTTP/1.1 Host: bieberfanclub.com Content-Type: application/x-www-form-urlencoded Cache-Control: no-cache name=Ronald If the application running bieberfanclub.com were running PHP, then the $_POST array would be an array containing an element called name with the value Ronald. There are three advantages to sending variables with POST: - ​POST data can be encoded in a particular character set, which isn’t the case with GET. - Because your variables are being sent in the message body, you’re not limited as to how much data you can send by the length of the URL. - ​POST allows you to upload files but GET does not. There is no difference in security between the two methods. There is no limit in the HTTP protocol on the length of the URL, but there are limits on browsers and other clients. As a general rule, don’t create a URL longer than 2000 characters. #### Sending POST Data When you want to make a POST request to another application, you need to take responsibility for encoding the variables into the body. The simplest way to do this iswith the curl extension.[7](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-108) Curl supports several protocols and makes it easy to set up your request exactly as you want it. Using curl involves the following process: 1. 1. Initialize a curl session. 2. 2. Set options for the session. 3. 3. Execute the session (make the call). 4. 4. Close the session and release the resource. Let’s look at how you can use curl to set up the request you looked at before, where you POSTed the variable name containing the value Ronald to the Bieber fan club. 'Ron']; // Tell curl to do a application/x-www-form-urlencoded POST curl_setopt($curlResource, CURLOPT_POST, true); // We specify the values to POST curl_setopt($curlResource,CURLOPT_POSTFIELDS, $postData); // Execute the request and store the response $response = curl_exec($curlResource); // If there is an error it will be stored in $err $err = curl_error($curlResource); // Close the handle curl_close($curlResource); If you run this code, you will be able to see the result at [ https://requestb.in/13fkcqj1?inspect ](https://requestb.in/13fkcqj1?inspect). Tip It is possible to pass curl_setopt() an array of all the options you want to set instead of calling it multiple times. ### GET ​GET requests are typically used to get either a single entity or a collection of entities from a server. You can think of it as reading data from the server. #### Receiving GET Data Variables sent in a GET request are encoded into the URL. Here is an example of how variables are encoded into a URL: ​ [ http://bieberfanclub.com/topfan.php?name=Ron&rank=cheerleader ](http://bieberfanclub.com/topfan.php?name=Ron&rank=cheerleader) The variables begin with a question mark and are delimited by ampersand symbols. Each variable is a key-value pair with the equals sign denoting the value. PHP will automatically make variables passed in the URL available in the $_GET superglobal. It is possible to pass arrays through GET using syntax like this: ​ [ http://example.com/users.php?sort[col\]=name&sort[order]=desc ](http://example.com/users.php?sort[col]=name&sort[order]=desc) You would be able to access these variables like this: ['Ron', 'Jonathan', 'Anne Frank']]; // fans%5B0%5D=Ron&fans%5B1%5D=Jonathan&fans%5B2%5D=Anne+Frank echo http_build_query($getData); The http_build_query() function converts an array to a properly URL-encoded query string. The HTTP specification for the URL only allows a very limited set of characters to be used. Any character that is not in this set must be encoded.[8](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-109) PHP provides the urlencode() function, which will properly encode a string to be used as part of a URL. The urldecode() function will convert an encoded string back to its original representation. ['Ron', 'Jonathan', 'Anne Frank']]; // fans%5B0%5D=Ron&fans%5B1%5D=Jonathan&fans%5B2%5D=Anne+Frank $encodedString = http_build_query($getData); // fans[0]=Ron&fans[1]=Jonathan&fans[2]=Anne Frank echo urldecode($encodedString); In this example, we're decoding the properly URL-encoded string that http_build_query() generated so that we can see how an array is encoded in a parameter. ### PUT ​PUT requests are used to replace an entire entity or collection. Typically, a PUT request will require you to specify all the mandatory attributes of an entity. It is a write operation because it replaces an entity with the state that you provide. ​PATCH requests are similar in that they are used to replace data, but a PATCH request will only replace the part of the entity that you provide. For example, if a user has a name, surname, and e-mail field, you will be able to use a PATCH request to change just one of those fields while leaving the others the same. API servers often don’t implement PATCH and rather require you to use PUT. #### Receiving PUT Data PHP does not make a superglobal available for PUT. To get access to it, you need to read the php://input stream. You can use the parse_str() function to convert it into an array: "Ron"]; $curlResource = curl_init(); $options = [ CURLOPT_URL => 'https://requestb.in/oxk2utox', CURLOPT_CUSTOMREQUEST => 'PUT', CURLOPT_POSTFIELDS => $data ]; curl_setopt_array($curlResource, $options); $response = curl_exec($curlResource); In the previous example, we are telling curl to make a PUT request and we stipulate the values to pass exactly as we did for POST. Notice that we are using the curl_setopt_array() function to set multiple curl options at once instead of calling curl_setopt() multiple times. ## Sessions HTTP is a stateless protocol, which means that the connection between the client and the server is lost once the transaction ends. Furthermore, PHP terminates when it finishes processing a request and its application state is lost. A session is a means for the server to persist application state for consecutive requests from a visitor. Information like whether the user is logged in can be stored in the session. Another example of where a session could be used is with an online shopping site, where the contents of the visitor’s shopping cart could be stored in a session. Session information is stored on the server and is associated with a unique identifier. The client will send the session identifier to the server with every request and this allows the server to associate the request with a particular session. If you have multiple web servers, then you’ll need to find a way to either share the session information between them or ensure that a visitor isalways directed to the server that holds her session information. Web sites that don’t need to remember who a user is or keep any preferences don’t need to use sessions. An example of such a site would be one that serves static content that is the same for all visitors. PHP supports sessions by default, but they can be disabled through a configuration setting in php.ini. ### Starting a Session A session in PHP is started when you call the function session_start() or automatically if your php.ini configuration specifies session.auto_start = 1. If you are using session_start(), then you must make sure that you call this function before any output is sent to the client. When the session starts, the user is assigned a random unique session identifier called the session id. The session ID is either stored in a cookie on the client or passed through the URL if you enable the session.use_trans_sid configuration setting. Accepting sessions from the URL can be risky and it is better to configure PHP to only use cookies with the session.use_only_cookies setting. Chapter [6](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-11) on security has more information about this. ### Session Identifier and Session Variables The session extension makes available the SID predefined constant that holds the session identifier. You can also use the session_id() function to get or set it. You can use the function session_regenerate_id() to make a new session identifier for a client. You should call this immediately after calling session_start() to help protect against session fixation. Once a session has started, the superglobal $_SESSION is available as an associative array containing the session variables. ### Ending a Session To properly end a session, you should do three things: 1. 1. Set the $_SESSION array to an empty array. 2. 2. Set the session cookie expiry time to the past. 3. 3. Call the function session_destroy(). The effect of Step 2 is to let the client browser know that it can delete the cookie containing the session identifier. There is no guarantee that the client will do so, however. Of course, if you’re not using cookie-based sessions then there is no need to do this. ### Session Handlers PHP supports creating your own session handler, but by default PHP sessions are stored on disk and use the serialize() and unserialize() commands to encode and decode the data. In addition to disk-based sessions, PHP also ships with a memcached session handler that can be configured in php.ini. If you want to write your own session handler, you should implement the SessionHandler interface. This will let you use alternative ways of storing your sessions and customize how you encode and decode the session data. ## File Uploads We’ll focus on how file uploads work and the PHP syntax associated with them in this section. Make sure that you study the section on file uploads in Chapter [6](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-11) in conjunction with this section. Forms allow files to be uploaded by means of a “multi-part” HTTP POST transaction. You can specify that you want to encode your POST using multi-part form data in your HTML by declaring a form something like this: Note that I've left the "action" attribute blank. By default, an HTML form will submit to the URI that it is served from. ### Limiting the Size of Uploads You do not want people to be able to upload massive files that fill up your disk. To manage the size of files that people can upload, you can limit the size in the browser and on the server. To tell the client to limit the size of the upload, you can add an input to your form like this: Limiting the size in the browser should be done just to improve user experience. It is very simple for a user to disable or change the limit to bypassthe limit. You should rather configure PHP to limit the size of a POST operation. The post_max_size setting limits the maximum of data any POST may contain. The upload_max_filesize is applied to limit the size of files that can be uploaded. ### Temporary Files PHP stores the uploaded file in a temporary location and makes it available to the script that the form POST'ed to. You can process the file in the temporary location and then optionally move it to a permanent location. PHP will automatically delete the temporary file when the script finishes running so if you want to keep it you must move it. In addition to creating the temporary file, PHP will populate the $_FILES superglobal array. Each file that was uploaded in the form will have an entry in the array. You need to be aware that the information in the $_FILES array can quite easily be spoofed so you should manually validate every piece of information. Each file be represented by an array in the $_FILES superglobal and will key for the name, type, size, temporary filename, and error code. | Key| Description| | -------- | ------------------------------------------------------------ | | name | The original name of the file stored on the client | | type | The MIME type provided by the client | | size | The size in bytes of the file| | tmp_name | The name of the file in its temporary location | | error| An error code, or UPLOAD_ERR_OK if the upload was successful | Note Chapter [6](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-11) has more information on dealing with file uploads. ## Forms Forms allow users to submit data to your PHP script. When declaring a form in HTML, you specify the method it uses to send information to the server. Although you can choose GET or POST, you should make sure that you choose a request method that matches what you intend to do. PHP automatically makes form data available to your script in one of two superglobals—$_GET or $_POST—depending on which method the form used to make the request. ### Form Elements These superglobals can easily be edited by the client and so should always be filtered carefully and not trusted. Dots and space in form field names are converted to underscores. As an example, consider the HTML input tag: The value that it contains will be placed in either $_GET['email_address'] or $_POST['email_address'] depending on the forms method. ### Arrays in HTML Forms Form data can be turned into an array using syntax like this in HTML: ​ ​ This will result in $_POST or $_GET being an array that looks like this: array( 'name' => array( 'first' => '', 'last' => '' ) ) One of the most useful ways that arrays help is in grouping inputs together. Consider a checkbox that can have multiple values:

What pets do you want in your home?

Lots of Cats Just a dog If the person checked both boxes before submitting the form, then the $_GET or $_POST array will contain the following: array( 'pets' => array('cats', 'dog') ) This makes checkboxes a lot neater and easier to use. You can read more about this in the PHP Manual.[9](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-110) ### Selecting Multiple Items from a List Last, you will need to use an array if you want the user to be able to select multiple items from a select list: Note that the name of the select is an array, so each value that the user selects will be added to the "var" array in your superglobal array. ## Cookies Cookies let you store a small (4 to 6 KB) amount of data on the client device. The client will read them and send them with each request. You can store any sort of information in a cookie, but they are most commonly associated with sessions. PHP can store its session identifier in the cookie. The session information is stored on the server and matched to the client through the identifier in the cookie. PHP doesthis for you when you start your session. By default, PHP session cookies are valid until the person closes their browser. You cannot control cookies on the client device. They can be edited or deleted at any time by the client. This means that you should neither trust the information sent with them nor rely on them to exist. You should also not store sensitive information in cookies. If you want to delete a cookie, you can set an expiry date that is in the past. This will let the client know that the cookie is no longer needed and can be deleted. You have no guarantee that the client will respect this. A server will set a cookie using the Set-Cookie response header. The client will include it with future requests using the Cookie request header. ### Setting Cookies The setcookie() function is used to set a cookie. The parameters are explained in the PHP Manual and are given in the order of this table: | Parameter | Used For | | --------- | ------------------------------------------------------------ | | value | Storing a scalar value in the cookie. | | expire| Unix epoch timestamp when the cookie expires. You can't rely on the cookie existing until it expires, as it is common for people to delete their cookies. | | path| The base path on the domain that the cookie will be available on. If you set it to /, then it will be available on all paths; otherwise, it will be available on the path and all sub-paths from it. | | domain| The cookie will be available on this and all sub-domains under it. You can only set a cookie that matches the domain the cookie is being served from. | | secure| Tells the client that it should only send the cookie if it is being sent over an HTTPS encrypted connection. | | httponly | Tells the client that it should only send the cookie using HTTP and not make it available to scripting languages like JavaScript. To a limited degree, this can help reduce XSS and session fixation attacks on clients that support it. | Cookies can only store scalar values. You can, however, use syntax like the following example: jlm5od9ngqi3krmu6fkjcebcb4 ​[user] => Array ( ​ [name] => Alice ​ [email] => [email protected] ) ) Note that user is an array and that the cookie value also contains the PHP session identifier. ### Retrieving Cookies You can access the cookie information using the $_COOKIE superglobal. Remember that this array is populated with information from the cookie sent by the client. This means that if you use setcookie() to create or change a cookie, the $_COOKIE array will only contain the new information when the client makes a new request. ## HTTP Headers HTTP headers are sent with the request from the client and with the response from the server. They are used to convey information about the HTTP message such as what sort of information is being provided and what will be accepted in return. HTTP headers take the form of a name-value pair in a clear text string. A carriage return and line feed character follows each header. There is no limit in the standard but most servers and clients impose limits on the length of a header and the total number of headers that may be sent in one request/response. PHP will automatically emit valid headers for you, but there are several cases where you may want to send your own header. ### Sending Headers The PHP function header() lets you send a header to the client. You may only send headers before any normal content has been sent to the client. One of the reasons that it is common to omit the closing ?> tag in included PHP files is to avoid having a newline character occur after the tag. This character would be sent as HTML content and would prevent you from being able to send headers. The parameters sent to header() are as follows: Parameter Description Header string String containing the header to set. For example, "Cache-Control: no-cache, must-revalidate". Replace Boolean to indicate whether this header must replace a previously sent header with the same name. Response code The HTTP response code to send with the header. There are two special cases for headers. The first is for headers that begin with the string "HTTP/". These can be used to explicitly set the HTTP response code, as in this example from the PHP manual[10](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-111): Hello {$_SERVER['PHP_AUTH_USER']}."; echo "You entered {$_SERVER['PHP_AUTH_PW']} as your password."; } In this example, we just output the contents of the variables in the $_SERVER array, but in real life we would perform some form of authentication. The password sent by the client is base64encoded to standardize the character set, but there is no hashing or encryption performed. This is a very weak form of protecting your site and unless you are using HTTPS, the password will be readable by anybody between your client and server. ## HTTP Status Codes HTTP status codes are sent with responses and follow standards set by the Internet Engineering Task Force, as well as de facto standards used within the industry. HTTP status codes are divided into ranges of 100 codes each. All of the status codes in the range will have a similar meaning, as in thisfollowing table. | Range | General Meaning | | ----- | ------------------------------------- | | 200 | The request was successful | | 300 | The request needs to be redirected| | 400 | There was an error on the client side | | 500 | There was an error on the server side | You won’t need to know all of the different status codes by heart for your exam. When you’re writing an API in real life, you’ll be able to visit Wikipedia[12](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-113) and choose the right code for your response. For your exam, you just need to know the most important ones: | Code | Status | | ---- | ------------------------------------------------------------ | | 200 | OK; the request was successful. | | 201 | Created; the request resulted in a new resource being created. | | 301 | Moved permanently; the resource will always be found at the location specified. | | 400 | Bad request; there was something in the request that was malformed or otherwise prevented its execution. | | 401 | Unauthorized; the client has not been authenticated as being allowed to make this request. | | 403 | Forbidden; the (authenticated) client is not allowed to make this request. | | 418 | I’m a teapot; the client is attempting to send coffee making protocols to the server, which is in fact a teapot.[13](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-114) Okay this isn’t an important status code, but it’s fun to know about. | | 500 | Internal server error; the server was not able to complete the request and can’t respond more appropriately. Commonly associated with a crash or misconfiguration. | When using APIs the HTTP status code is very important. If you’re coding an API, you should make sure that you send the correct status code for the error. For example, if the request failed and you send an error message in the body, you should make sure that the HTTP status code is 400 and not 200. As you work with PHP, you’ll become more familiar with the status codes, but if in doubt, you should look up a list and make sure that you’re sending an appropriate response. ## Output Control Functions Instead of outputting from your script immediately, it is often very useful to store your output in a buffer and then flush the whole buffer at once. This could be useful for escaping output before sending it to the user, or using PHP's built-in compression routines to compress the response you send to compatible browsers. The ob_start() function is used to start output buffering. Anything that your script would normally output in the body of the response will be stored into the buffer. This function takes an optional parameter, which is a callable and will be called when the buffer is either output or discarded. Here is an example of setting a callback function. I've included the output of the script as a comment. alert("xss");</script> echo '<script>alert("xss");</script>'; In this example, the buffer was implicitly flushed when the script ended. You can use the ob_flush() function[14](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-115) to explicitly flush the buffer and output its contents. One time that this could be useful is when you're writing a CLI script and want to be able to see progress, and another (arguably bad) use case could be to write the server for a long-polling JavaScript client. {"string": "my json api output is compressed now"} Chapter [9](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-101) Quiz Q1: Assume that the variables_order is set to the PHP default. What would the value of $_REQUEST['biggestfan'] be for the following HTTP request? POST HTTP/1.1 Host: thebeebfanclub.com?biggestfan=Ron Content-Type: application/x-www-form-urlencoded Cache-Control: no-cache biggestfan=Ronald Ron Ronald Something else None of the above Q2: Each of these inputs is in a properly constructed form that POSTs to your site. Which one is the correct way in which to place the name entered into the input box into a variable that you can access like this $_POST['justin]['numberonefan']? None of the above

Q3: Cookies are a reliable way to store information without wasting server resources. Choose the most correct option.

Yes, storing information on the client side saves server disk space
No, a copy of the information is still kept in the session data
No, they are not reliable
Yes, it is common to store all of the session data in cookies

Q4: What will this code output? Choose all that apply

100 ORDER BY price DESC You can specify multiple column names separated by commas or use the wildcard * to receive all columns. The format of the data that PHP receives is dependent on the driver and function that you use to call the query. You’ll generally receive an object or an array that has keys/properties corresponding to the columns. ### Inserting New Data The INSERT statement is used to create new rows in the database. You will need to provide a list of the columns and the values to insert to them. Columns that are marked NOT NULL are mandatory and must have a value specified when you create the row. INSERT INTO products (name, price, category_id) VALUES ('cheeseburger', 100, 3) If you don’t specify the names of the columns, SQL will assume that you’re providing values in the order that the columns appear in the table. This can be a drawback if ever you change the structure of your table. Otherwise, as in the example, you specify the names of the columns, and then the values. The values are assigned to the columns in order. So, in thisexample the name of the product is set to 'cheeseburger', its price is 100, and it is placed into the category that has an ID value of 3 (whatever that may be). ### Updating Data The UPDATE statement accepts a list of values similar to the INSERT statement, as well as an optional WHERE clause similar to the SELECT statement. You must specify what values to update the existing data to, and the criteria for the rows that must be updated. UPDATE products SET price = price + 100 WHERE category_id = 3; ### Aggregating Data You can use the database to perform calculations and send you the results. | Statement| Returns| | -------------- | ---------------------------------- | | AVG | Average value of the data values | | SUM | Total of all the data values found | | COUNT| How many records were found | | DISTINCT COUNT | How many unique records were found | | MIN | The lowest value in the data set | | MAX | The highest value in the data set | Using these functions looks as follows: SELECT AVG(price) FROM products; ### Grouping Data You can tell SQL to group data by a column or combination of columns before returning it to you. This is often useful in conjunction with the aggregating functions. Let’s consider an example where we want to find out the total amount of sales that each of our customers has purchased. SELECT email, SUM( sales_value ) ​FROM `transactions` ​GROUP BY email In this example, we group transactions that have the same e-mail address. The SQL database engine will apply the SUM statement by adding the sales values in each group and then returning that. I included the e-mail address in the SELECT statement so that the output will have the e-mail address of the customer, and the sum of all the sales values of transactions with their e-mail address. ## Joins Joins are used to connect tables based on supplied criteria. This lets you retrieve information from related tables. In the products and categories database, you can retrieve the category name of products by joining the categories table to the products table: SELECT * FROM products JOIN categories ON categories.id = products.category_id We are joining the categories table to the products table and giving instructions to SQL on how to match rows. A row from the categories table will be included if its id column matches the category_id column in the products table. ### Join Types There are several ways to join tables. | Join Type | Effect | | ---------------- | ------------------------------------------------------------ | | INNER JOIN | Selects records that have matching values in both tables, as in the previous example | | LEFT OUTER JOIN | Selects tables from the left table that have matching right table records | | RIGHT OUTER JOIN | Selects records from the right table that have matching left table records | | FULL OUTER JOIN | Selects all records that match either left or right table records | These joins can be represented diagrammatically, as shown in Figure [10-2](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-44). ![A456636_1_En_10_Fig2_HTML.jpg](file:///home/antonio/Escritorio/PHP%207%20Zend%20Certification%20Study%20Guide%20-%20Andrew%20Beak.htmlz_FILES/images/000008.jpg) Figure 10-2. Many ways to join tables ## Prepared Statements When you issue a command to a SQL engine, it must parse the command in order to execute it. After the statement has been executed, SQL will discard the compiled code with the result that repeated calls with the same SQL command will need to be parsed individually. Obviously, this results in duplicated effort. You can save SQL from having to repeat its efforts by using prepared statements that become parsed code templates that SQL stores for multiple reuse. Prepared statements also offer significant security advantages. Parameters are bound to the prepared statement, and are not included as part of the code string. This means that it is not possible for your parameters to intrude on the code, which means that you no longer need to worry about escaping code to prevent SQL injection. Just keep in mind the possibility of stored XSS attacks before you stop worrying about escaping data coming into or out of your database. prepare("INSERT INTO users (username, password) VALUES (?, ?)"); $stmt->bind_param("ss", $username, $password); // set parameters $username = "bob"; $password = password_hash("password", PASSWORD_BCRYPT); // run the statement $stmt->execute(); ## Transactions A transaction is a set of SQL statements that will either all succeed or else have no effect. After a transaction finishes the database must not have any table constraints invalidated and must be in a state where all the changes have been persisted. A database must have some way of ensuring that transactionscan run at the same time and not interfere with each other, for example, by incrementing a primary key that another transaction is depending on. In summary, a transaction is a set of SQL statements that must complete successfully in an “all or nothing” manner. After it runs the database must be in a consistent state and must be recoverable from error. The syntax for transactions varies between vendors, but there are three important statements. - One statement will mark the beginning of the transaction block. The SQL statements following this will be part of the transaction. - There are two statements that can end a transaction. One of them will tell SQL to go ahead and make all the changes that the transaction is making. - The other end statement will tell SQL that for whatever reason you want to abandon the transaction and rather revert to the state the database wasin when the transaction started. Here are the three most common vendor statements: | MySQL | MS-SQL | ORACLE | | ----------------- | ------------------ | ----------------- | | START TRANSACTION | BEGIN TRANSACTION | START TRANSACTION | | COMMIT | COMMIT TRANSACTION | COMMIT | | ROLLBACK| ROLLBACK WORK| ROLLBACK| ## PHP Data Object (PDO) The PDO is a data abstraction layer that offers a single interface for you to interact with multiple data sources. While using the PDO, you can use the same functions to interact with your database, no matter the vendor. It’s important to understand that PDO is an access abstraction layer and does not abstract SQL or data types. The SQL that you pass to the PDO::query() or prepared statements must be valid for the vendor you are connecting to. PDO uses database adapters to connect to the database. These adapter classes implement PDO interfaces and expose vendor-specific functions as regular extension functions. PDO is configured in the PHP configuration file. At runtime, you can change options with the PDO::setAttribute() function. The PDO extension makes several predefined constants available. You won’t need to remember them all for the Zend examination, but look through the PHP manual and familiarize yourself with them. The PDO will emulate prepared statements for databases that don’t support them, but will otherwise use the native prepared statement functionality of the database. ### Connecting to PDO To connect to the database with PDO, you create an instance of the PDO class. The constructor accepts parameters for the database source (DSN) and the username/password if these are required. getMessage(); } If there are errors connecting to the database then a PDOException will be thrown. It is very important to note that the stack trace of the exception will probably contain the full database connection details. Make sure that you catch it and don’t let it be displayed RAW. To close a connection when you're done with it, you can set the PDO variable to null. $dbh = null; Database connections are automatically closed at the end of your running script unless you make them persistent. Persistent database connections are not closed but are instead cached for another instance of the script to use. This reduces the overhead of needing to connect to the database every time your web application runs. ### Transactions in PDO PDO offers transaction commands too, but does not emulate proper transaction handling. This means that you can only use the PDO transaction functions on databases that natively support transactions. The functions are PDO::beginTransaction(), PDO::commit(), and PDO::rollBack(). setAttribute(PDO::ATTR_EMULATE_PREPARES, TRUE); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $password = password_hash("password", PASSWORD_BCRYPT); try { $pdo->beginTransaction(); $pdo->exec(" ​ INSERT INTO users ​ (username, password) ​ VALUES ​ ('bob', '{$password}'"); // some more update or insert statements $pdo->commit(); } catch (PDOException $e) { $pdo->rollBack(); echo 'Rolled back because: ' . $e->getMessage(); } In the example, we make a connection to the database with PDO and start a transaction. We wrap all the PDO transaction functions in a try...catch block. If a PDO statement fails to run, it will throw a PDOException. We use the catch block to roll back the transaction. ### Fetching PDO Results We use the PDO::fetch() method[2](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-45) to retrieve data from a PDO result. PDO will maintain a cursor to traverse the result set and will use this to determine which element to return to you. PDO will return the data to you in a format that you specify in the first parameter to fetch(). | Fetch Style| Returns| | ---------------- | ------------------------------------------------------------ | | PDO::FETCH_ASSOC | Returns an associative array with your database columns as keys. | | PDO::FETCH_NUM | Returns an array indexed by column number as returned by your result set. | | PDO::FETCH_BOTH | Returns an array with both the indexes of ASSOC and NUM style fetches. | | PDO::FETCH_BOUND | Returns true and assigns the values of the columns in your result set to the PHP variables to which they were bound with the PDOStatement::bindColumn() method. | | PDO::FETCH_CLASS | Returns a new instance of the requested class mapping the columns of the result set to named properties in the class. | | PDO::FETCH_INTO | Updates an existing instance of the requested class, mapping as for FETCH_CLASS. | | PDO::FETCH_OBJ | Returns an anonymous object with property names that correspond to the column names from your result set. | | PDO::FETCH_LAZY | Combines PDO::FETCH_BOTH and PDO::FETCH_OBJ and creates the object variable names as they are accessed. | | PDO::FETCH_NAMED | As for PDO::FETCH_ASSOC, returns an associative array. If there are multiple columns with the same name, the value referred to by that key will be an array of all the values in the row that had that column name. | ### Prepared Statements in PDO Not all database engines support prepared statements and this is the only feature that PDO will emulate for adapters that don't. The syntax for a prepared statement in PDO is very similar to using a native function. prepare("INSERT INTO users (name, email) VALUES (:name, :value)"); $stmt->bindParam(':name', $name); $stmt->bindValue(':email',’[email protected]’); // insert one row $name = 'one'; $stmt->execute(); Walking through the example, we see that the prepare() method is used to create the statement object. We’re using two different forms of binding parameters to demonstrate the difference. In the first, bindParam(), we're binding a variable to the statement parameter. When the statement executes, the parameter will take the value of the variable at execution time. The second way to bind variables, bindValue(), binds a literal to the statement parameter. If you used a variable name in bindValue(), then the value of the variable at bind time is used. Changes to the variable before the statement executes will not affect the parameter value. You can also pass the values to bind as an array in your call to execute, as in this example: prepare('SELECT * FROM users WHERE email = :email AND status=:status'); $stmt->execute(['email' => $email, 'status' => $status]); $user = $stmt->fetch(); Only values can be bound in a SQL statement, not entities like table names or columns. You can only bind scalar values, not composite variables like arrays or objects. ### Repeated Calls to PDO Prepared Statements You have seen that the bindParam() method inserts the value of a variable at the time the statement is executed into the statement parameter. You can see that using bindParam() allows you to repeatedly call the prepared statement, using different values for the parameters on each call. The method closeCursor() is used to clear the database cursor and return the statement to a state where it can be executed again. Some databaseshave problems executing a prepared statement when a previously executed statement still has unfetched rows. Chapter [10](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-41) Quiz Q1: You can use the ____________ function to build an HTTP query string suitable to use for GET or POST out of an array. | http_build_query() | | ------------------ | | http_build_param() | | parse_url()| | urlencode()| Q2: The PHP function encodeurl() is used to: | Make sure that an URL is UTF-8 encoded. | | ---------------------------------------------------------- | | Convert reserved characters in a URL to % encoded symbols. | | Build a string suitable for GET parameters from an array. | | There is no such PHP function. | Q3: What are the advantages of using prepared statements; choose as many that apply? | They can be more secure than using normal queries. | | --------------------------------------------------------- | | They are faster for repeated queries. | | You can use the same query in different database vendors. | | None of the above. | Q4: I have information about customers stored in a table. Each row has an account_id that is a foreign key to a table called accounts. How can you select the postcode column from the address table for a customer with ID 123? | SELECT `postcode` FROM `accounts` WHERE customer_id = 123; | | ------------------------------------------------------------ | | SELECT `postcode` FROM `accounts` AS `acc`JOIN `customers` as `cust` ON `cust.id` = `acc.id` WHERE `c`.id = 123 | | SELECT `postcode` FROM `accounts` AS `a`JOIN `customers` as `c` ON `c.account_id` = `a`.`id` WHERE `c`.id = 123 | | SELECT `postcode` FROM `accounts` AS `a`FULL OUTER JOIN `customers` as `c` ON `c.id` = `a.id` WHERE `c`.id = 123 | Footnotes [1](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-46) ​[ https://dev.mysql.com/doc/refman/5.7/en/integer-types.html ](https://dev.mysql.com/doc/refman/5.7/en/integer-types.html) [2](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-47) ​[ https://secure.php.net/manual/en/pdostatement.fetch.php ](https://secure.php.net/manual/en/pdostatement.fetch.php) © Andrew Beak 2017 Andrew BeakPHP 7 Zend Certification Study Guide[https://doi.org/10.1007/978-1-4842-3246-0_11](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-97) # 11. Error Handling Andrew Beak1 (1) Grafham, Cambridgeshire, UK Error handling accounts for some of the biggest changes between PHP 5.6 and PHP 7.1 and it makes sense to address this important topic separately even though we have touched on it at relevant places elsewhere in thisbook. ## Throwables We’re going to be looking at the Error and Exception classes in this chapter. For now, all that you need to know is that they both implement the Throwable interface that was introduced in PHP 7. Tip The reason that PHP defined a new Error class that does not extend the Exception class was to maintain backward compatibility with PHP5.6 code. ### The Throwable Interface Exceptions and error exceptions both implement the Throwable interface, so you can catch both types in a single block like this: getMessage(); } Thisscript will output a notice error for the attempt to access an invalid variable. Trying to call a function that does not exist would result in a fatal error in earlier versions of PHP, but in PHP 7.1, you can catch it. Here is the output for the script: Notice: Undefined variable: thisVariableIsNotSet in /in/lQC3F on line 5 Error caught: Call to undefined function badFunction() ### Error Constants PHP has a lot of constants[2](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-559) that are used in relation to errors. These constants are used when configuring PHP to hide or display errors of certain classes. Here are some of the more commonly seen error codes: | Code | Description| Script | Throws Error? | | ------------------- | ------------------------------------------------------------ | ------------------------------------------------- | ------------- | | E_DEPRECATED | The interpreter will generate warnings of this type if you use a language feature that is deprecated. | Continues to run| No | | E_STRICT | Similar to E_DEPRECATED, this indicates that you are using a language feature that is not currently standard and might not work in the future. | Continues to run| No | | E_PARSE | Your syntax could not be parsed and so your script won’t start. | Won’t run at all| No | | E_NOTICE | An informational message. | Continues to run| No | | E_WARNING | These are non-fatal warnings.| Continues to run| No | | E_ERROR | The script cannot continue to run and is being terminated. | Aborts unless you handle it with an error handler | Yes | | E_RECOVERABLE_ERROR | The error was probably dangerous enough to be fatal but the engine is not in a state where it cannot continue. | Aborts unless you handle it with an error handler | Yes | ### Using an Error-Handler Function The set_error_handler() function[3](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-560) is used to tell PHP how to handle standard engine errors that are not instances of the Error exception class. You cannot use an error-handler function for fatal errors; you must catch them as Error exceptions. ​set_error_handler() accepts a callable[4](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-561) as its parameter. Callables in PHP can be specified in two ways: Either by a string denoting the name of a function, or by passing an array that contains an object and the name of a method (in that order). Note You can specify protected and private methods in an object as the callable. You can also pass null to tell PHP to revert to using the standard error-handling mechanism. If your error handler does not terminate the program and returns, then your script will continue executing at the line after where the error occurred. PHP passes parameters to your error-handler function. You can optionally declare these in the function signature if you want to use them in your function. getMessage(); } /* Error #[2] occurred in [/in/Xa0Td] at line [11]: [Division by zero] */ In the preceding example, we divide the number five by zero. In PHP this results in a warning so an Error is not thrown. We have, however, set the function myHandler() up as the customer error handler and so it is invoked when PHP encounters the warning. Errors that cause the script to terminate cannot be caught with a user error handler; these include E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, and E_COMPILE_WARNING. ### Displaying or Suppressing Non-Fatal Error Messages Generally, you want to hide all system error messages while in production and your code should run without generating warnings or messages. If you are going to show an error message, make sure that it is one that you’ve generated and that does not include information that could help an attacker break into your system. In your development environment, you want all errors to be displayed so that you can fix all the issues that they relate to, but while in production you want to suppress any system messages being sent to the user. To accomplish this, you need to configure PHP using the following settings in your php.ini file: - ​ display_errors can be set to false to suppress messages - ​ log_errors can be used to store error messages in log files - ​ error_reporting can be set to configure which errors trigger a report The best practice is to gracefully handle errors in your application. In production, you should rather log unhandled errors instead of allowing them to be displayed to the user. Note We looked at the error suppression operator @ in the first chapter. Remember that it’s best to avoid using it. The error_log() function[5](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-562) can be used to send a message to one of the systems error-handling routines. You shouldn’t confuse it with the error_log configuration option. The configuration option specifies how to deal with logs, whereas the function is used to send a message. You can also use the error_log() function to send e-mails, but personally I would not do so and would rather do this in code or use a service like Rollbar.[6](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-563) ### Error-Handling Functions PHP has many functions[7](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-564)[8](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-565) that relate to error handling. This table provides a summary of them. We’ll be looking at most of them in this chapter. | Function| Purpose| | ------------------------- | ------------------------------------------------------------ | | debug_backtrace | Generates a backtrace. | | debug_print_backtrace | Prints a backtrace. Be careful when using this function because it can generate a lot of output! | | error_clear_last| Clears the most recent error.| | error_get_last | Gets the last occurred error.| | error_log | Sends an error message to the defined error-handling routines. | | error_reporting | Sets which PHP errors are reported.| | restore_error_handler | Restores the previous error-handler function. | | restore_exception_handler | Restores the previously defined exception-handler function. | | set_error_handler | Sets a user-defined error-handler function.| | set_exception_handler | Sets a user-defined exception handler function.| | trigger_error | Generates a user-level error/warning/notice message. | | user_error | Alias of trigger_error.| ## Exceptions Exceptions are a core part of object-oriented programming and were first introduced in PHP 5.0. An exception is a program state that requiresspecial processing because it’s not running in the expected manner. You can use an exception to change the flow of your program, for example, to stop doing something if certain preconditions are not met. An exception will bubble up through the call stack if you do not catch it. Let’s look at an example: getMessage(); } catch (ChildException $e) { // matches this class exactly echo "Child Exception :" . $e->getMessage(); } catch (Exception $e) { // matches this class because of inheritance echo "Exception :" . $e->getMessage(); } The output of this example is Parent Exception :My Message. In the example, we are throwing a ChildException, which inherits from ParentException, which in turn extends the base Exception class. The blocks are evaluated in order from top to bottom. The first block that is matched will be executed. The class of the exception being thrown is matched against the name of the class given as a parameter to the catch clause. The matching criteria are that the classes are either: - Exactly the same, or - The thrown exception is an ancestor of the exception in the catch statement In this example, we threw an exception of the ChildException, which inherits from the ParentException. The exception is therefore matched against the first catch block and the code is executed. I put the base Exception at the bottom of the list of catch blocks because all custom exceptions inherit from it, which makes it a catchall. ### The Exception Hierarchy So far, we’ve understood that Errors and Exceptions both implement the Throwable interface. We’ve just seen that both the Error and Exception class can be extended. The built-in PHP 7 exception hierarchy looks like this: interface Throwable |- Exception implements Throwable ​|- ... |- Error implements Throwable ​|- TypeError extends Error ​|- ArgumentCountError ​|- ParseError extends Error ​|- ArithmeticError extends Error ​|- DivisionByZeroError extends ArithmeticError ​|- AssertionError extends Error As you can see, there are several predefined error classes that form a hierarchy underneath Error. The following table summarizes their purpose: | Class | Purpose| | ------------------- | ------------------------------------------------------------ | | TypeError | A TypeError is thrown when the argument passed to a function does not match itscorresponding declared parameter type, or when the function does not return the expected type. | | ArgumentCountError | ArgumentCountError is thrown when too few arguments are passed to a user-defined function or method. | | ParseError| A ParseError is thrown when there is an error parsing PHP code, for example, when you call eval() or include a file. | | ArithmeticError | An arithmetic error occurs when you try to bitshift by a negative amount or make a call to intdiv() that would result in a value outside the limits of an integer on the current system. | | DivisionByZeroError | A DivisionByZeroError occurs if you try to divide by zero. | | AssertionError| An AssertionError is thrown when an assertion made with the assert() language construct fails. | ## Handling Exceptions Robust code can encounter an error and cope with it.[10](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-567) Handling exceptions in a sensible way improves the security of your application and makes logging and debugging easier. Managing errors in your application will also allow you to offer your users a better experience. In this section, we cover how to trap and handle errors that occur in your code. ### Catching Exceptions Remember that earlier in the chapter, we defined a ValidationException like this: getMessage(); } catch (Exception $e) { echo "General exception type caught"; } Note that there are two catch clauses. Exceptions will be matched against the clauses from top to bottom until the type of the exception matches the catch clause. Note The matching criteria are that the classes are either exactly the same or the thrown exception class is an ancestor of the Exception class in the catch statement. Since myValidation throws a ValidationException, we would expect it to be caught in the first block, but if any other type of exception is thrown in the function, then it will be caught in the second catch block. Note also the method getMessage() is being called on the exception object. Other methods in the basic Exception class will give error codes, stack traces, and other information. The PHP manual on Exceptions[11](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-568) is the best reference for the prototype for the exception object. It is possible to throw an exception in a catch block. This lets you catch an exception and then rethrow it, perhaps as a different type, if need be. Tip You should always order your catch blocks from most specific at the top to the most general at the bottom—remember that catch blocks are greedy! A catch block can specify multiple exception classes by separating them with a pipe (|) character. In the following example, the catch block will match exceptions that are of the MyException class or of the AnotherException class. getMessage(); } | Nothing, this code runs without error | | ------------------------------------- | | Oops! | | A PHP fatal error | | None of the above | Q4: What will this code output? > 1; | Syntax Error | | ------------ | | 0 | | 1 | | 2 | | 9 | Q5: The recommended production setting for the display_error configuration setting is On. | True | | ----- | | False | Q6: The session_generate_id() function is used to create a session identifier and should be called when a person logs in to help mitigate session fixation attacks. | True | | ----- | | False | Q7: When you call the json_encode function on an object to serialize it, which magic method will PHP call? | __sleep | | ------------- | | __wake | | __get | | __clone | | None of these | Q8: What will this script output? 2, 0 => "1", 2 => 3 ); $equal = $arr1 == $arr2 ? 'Equal' : 'Not Equal'; $identical = $arr1 === $arr2 ? 'Identical' : 'Not Identical'; echo "The arrays are [$equal] and [$identical]"; | Syntax error; this won't run | | ---------------------------------------------- | | The arrays are [Equal] and [Identical] | | The arrays are [Equal] and [Not Identical] | | The arrays are [Not Equal] and [Not Identical] | | The arrays are [Not Equal] and [Identical] | | None of the above | Q10: What will the output of this function be? name); $set = isset($a->surname); if ($empty === $set) { echo "Yes"; } else { echo "No"; } | Yes| | ---------------------------- | | No | | Syntax error; this won’t run | Q13: If you do not specify a visibility modifier, PHP chooses private by default so that your code is secure. | True | | ----- | | False | Q14: You can use the _____________ function to make sure that a variable is suitable to display and doesn't contain any spaces. | ctype_alpha | | ----------- | | ctype_print | | ctype_graph | | filter_var | Q15: What will this code output? "bananas" ? 'foo' : 'bar'; | foo | | ----------------- | | bar | | None of the above | Q25: Thisis a tricky question, so go through it carefully and predict the output of the code. Remember that the second parameter of md5() causes the hash to be returned in RAW binary format instead of as a hex string. getMethods()); | True | | ----- | | False | Q30: Assume that you are running this script from the command line, and not in a web-browser. What will the output be? $name = filter_var($value, FILTER_SANITIZE_STRING); } } $obj = new SetMissing(); $obj->example = "hello"; echo $obj->example . PHP_EOL; $obj->example = "hello"; echo $obj->example; | hellohello | | ------------------------------------------------------------ | | hellohello | | hellohello | | None of the above | Q31: If you implement the __sleep() function, you need to make sure that it returns an associative array containing the names and values of the instance variables you want to be serialized. | True | | ----- | | False | Q32: What will the output of this code be? kittyWalk(); | Yes please! | | ----------------- | | No thanks! | | Woof| | Purr| | None of the above | Q33: What is the output of this code? name); $set = isset($a->surname); if ($empty === $set) { echo "Yes"; } else { echo "No"; } | Syntax error; this won’t run | | ---------------------------- | | Yes| | No | | Fatal error| Q34: Are PHP keys case sensitive? What will the output of this script be? "apple", "B" => "banana"]; $arr2 = ["a" => "aardvark", "b" => "baboon"]; echo count($arr1 + $arr2); | They are not case sensitive; this will output 2| | -------------------------------------------------- | | They are case sensitive; this will output 4 | | PHP keys are converted to integers; this outputs 2 | | None of the above| Q35: What will this script output? "three"]; echo $arr[1]; | one | | ----------------- | | two | | three | | None of the above | Q38: Interfaces can only specify public methods, but your class can implement them however you like. | True | | ----- | | False | Q39: You can force sessions to be contained exclusively in cookies by using the _____________ configuration setting. | session.cookie_secure | | --------------------- | | session.use_cookies | | session.use_trans_sid | | None of the above | Q40: What is the output of this code? | | 3 | No, they are not reliable. | | 4 | A notice because$ais undefined (this outputs content), and a warning because$ais undefined (because headers were sent with the notice message). | | 5 | Prevent the browser from sending this cookie to other web sites. | ## Chapter[10](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-41): Databases and SQL | Question | Answer | | -------- | ------------------------------------------------------------ | | 1 | http_build_query() | | 2 | There is no such PHP function| | 3 | They can be more secure than using normal queries and they are faster for repeated queries | | 4 | SELECT `postcode` FROM `accounts` AS `a`JOIN `customers` as `c` ON `c.account_id` = `a`.`id`WHERE `c`.id = 123 | ## Chapter[11](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-97): Error Handling | Question | Answer | | -------- | ------------------------------------------------------------ | | 1 | [ https://3v4l.org/poDFC ](https://3v4l.org/poDFC) | | 2 | [ https://3v4l.org/4XK2R ](https://3v4l.org/4XK2R) | | 3 | [ https://3v4l.org/4KoKF ](https://3v4l.org/4KoKF) | | 4 | [ https://3v4l.org/q2K52 ](https://3v4l.org/q2K52) | | 5 | [ https://3v4l.org/ru5gu ](https://3v4l.org/ru5gu) | ## Chapter[12](file:///home/antonio/Escritorio/PHP 7 Zend Certification Study Guide - Andrew Beak.htmlz_FILES/index.html#calibre_link-176): Exercises | Question | Answer | | -------- | ------------------------------------------------------------ | | 1 | [ https://3v4l.org/HWd8N ](https://3v4l.org/HWd8N) | | 2 | [ https://3v4l.org/itFYF ](https://3v4l.org/itFYF) | | 3 | [ https://3v4l.org/suCYR ](https://3v4l.org/suCYR) | | 4 | [ https://3v4l.org/bZJ7h ](https://3v4l.org/bZJ7h) | | 5 | False| | 6 | False. The function should besession_regenerate_id(). | | 7 | None of these | | 8 | [ https://3v4l.org/iSeQU ](https://3v4l.org/iSeQU) | | 9 | [ https://3v4l.org/UWMp8 ](https://3v4l.org/UWMp8) | | 10 | [ https://3v4l.org/8vIFB ](https://3v4l.org/8vIFB) | | 11 | False| | 12 | [ https://3v4l.org/i4Goi ](https://3v4l.org/i4Goi) | | 13 | False. It’s public by default and visibility has nothing to do with code security. | | 14 | ctype_graph| | 15 | [ https://3v4l.org/N27Ao ](https://3v4l.org/N27Ao) | | 16 | [ https://3v4l.org/vaRbT ](https://3v4l.org/vaRbT) | | 17 | is_uploaded_file() | | 18 | [ https://3v4l.org/2J18W ](https://3v4l.org/2J18W) | | 19 | False;PUTis idempotent butPOSTis not. | | 20 | True | | 21 | mysqli_real_escape_string()| | 22 | [ https://3v4l.org/JG42J ](https://3v4l.org/JG42J) | | 23 | [ https://3v4l.org/vPhFh ](https://3v4l.org/vPhFh) | | 24 | None of the above; there is no