Ready for the next step?
Use the PHP School workshop documentation to build you own workshop and help teach others PHP!
Open Menu
The exercise type indicated how the exercise should be verified, each exercise must have a type. There are three types of exercise types as of writing CLI, CGI & CUSTOM. In this section we will detail what the verification process for each exercise type is.
When selecting your exercise type you must return the valid type and implement the respective interface.
You choose the CLI type if you want the user to interact with the $argv
and $argc
super globals.
Type | ExerciseType::CLI() |
Interface | PhpSchool\PhpWorkshop\Exercise\CliExercise |
Methods to implement | getArgs |
getArgs
should return an array of string arrays. These are the arguments to be passed to the PHP CLI executable. The number of arguments which can be returned is not limited. All arguments should be strings. If multiple sets of arguments are
specified then the program will be executed each time with those arguments.
<?php
namespace PhpSchool\MyWorkshop\Exercise;
use PhpSchool\PhpWorkshop\Exercise\AbstractExercise;
use PhpSchool\PhpWorkshop\Exercise\CliExercise;
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
class MyExercise extends AbstractExercise implements ExerciseInterface, CliExercise
{
...snip
/**
* @return array
*/
public function getArgs()
{
return [
['arg1', 'arg2', 'arg3'], //first execution
['run2-arg1', 'run2-arg2', 'run2-arg3'] //second execution
];
}
/**
* @return ExerciseType
*/
public function getType()
{
return ExerciseType::CLI();
}
}
This exercise would cause PHP to be invoked like so:
php solution.php 'arg1' 'arg2' 'arg3'
And then:
php solution.php 'run2-arg1' 'run2-arg2' 'run2-arg3'
You choose the CGI type if you want the user to interact with the $_GET
, $_POST
, $_SERVER
, etc super globals.
This exercise type allows to simulate a real HTTP request to a PHP script.
Type | ExerciseType::CGI() |
Interface | PhpSchool\PhpWorkshop\Exercise\CgiExercise |
Methods to implement | getRequests |
getRequests
should return an array of PSR-7 Requests. The number of requests is not limited. Check here for more information about PSR-7. The method is currently type hinted to return an array of the Psr\Http\Message\RequestInterface interface. You will need to use a library which implements the PSR-7 standard. Currently zendframework/zend-diactoros is shipped with php-school/php-workshop
so you can just use that, or feel free to pull in a different implementation.
<?php
namespace PhpSchool\MyWorkshop\Exercise;
use PhpSchool\PhpWorkshop\Exercise\AbstractExercise;
use PhpSchool\PhpWorkshop\Exercise\CgiExercise;
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
use Psr\Http\Message\RequestInterface;
use Zend\Diactoros\Request;
class MyExercise extends AbstractExercise implements ExerciseInterface, CgiExercise
{
...snip
**
* @return RequestInterface[]
*/
public function getRequests()
{
return [
(new Request('http://www.my-library.com?genre=punk&limit=50'))
->withMethod('GET')
];
}
/**
* @return ExerciseType
*/
public function getType()
{
return ExerciseType::CGI();
}
}
The request above will result in PHP super globals looking something like this:
//$_SERVER
array(13) {
["HTTP_HOST"] => string(18) "www.my-library.com"
["SCRIPT_FILENAME"] => string(57) "/root/path/your-workshop/get-solution.php"
["PWD"] => string(40) "/root/path/your-workshop"
["REDIRECT_STATUS"] => string(3) "302"
["SHLVL"] => string(1) "1"
["CONTENT_LENGTH"] => string(1) "0"
["QUERY_STRING"] => string(19) "genre=punk&limit=50"
["REQUEST_METHOD"] => string(3) "GET"
["_"] => string(48) "/usr/local/bin/php-cgi"
["__CF_USER_TEXT_ENCODING"] => string(13) "0x1F5:0x0:0x0"
["PHP_SELF"] => string(0) ""
["REQUEST_TIME_FLOAT"] => float(1458634262.4929)
["REQUEST_TIME"] => int(1458634262)
}
//$_GET
array(2) {
["genre"] => string(4) "punk"
["limit"] => string(2) "50"
}
<?php
namespace PhpSchool\MyWorkshop\Exercise;
use PhpSchool\PhpWorkshop\Exercise\AbstractExercise;
use PhpSchool\PhpWorkshop\Exercise\CgiExercise;
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
use Psr\Http\Message\RequestInterface;
use Zend\Diactoros\Request;
class MyExercise extends AbstractExercise implements ExerciseInterface, CgiExercise
{
...snip
/**
* @return RequestInterface[]
*/
public function getRequests()
{
$request1 = (new Request('http://www.my-library.com?genre=punk&limit=50'))
->withMethod('POST')
->withHeader('Content-Type', 'application/x-www-form-urlencoded');
$request1->getBody()->write(urlencode(['genre' => 'punk', 'limit' => 200]));
return [$request1];
}
/**
* @return ExerciseType
*/
public function getType()
{
return ExerciseType::CGI();
}
}
The request above will result in PHP super globals looking something like this:
//$_SERVER
array(14) {
["HTTP_HOST"] => string(18) "www.my-library.com"
["SCRIPT_FILENAME"] => string(58) "/root/path/your-workshop/get-post-solution.php"
["HTTP_CONTENT_TYPE"] => string(33) "application/x-www-form-urlencoded"
["PWD"] => string(40) "/root/path/your-workshop"
["REDIRECT_STATUS"] => string(3) "302"
["SHLVL"] => string(1) "1"
["CONTENT_LENGTH"] => string(2) "17"
["CONTENT_TYPE"] => string(33) "application/x-www-form-urlencoded"
["REQUEST_METHOD"] => string(4) "POST"
["_"] => string(48) "/usr/local/bin/php-cgi"
["__CF_USER_TEXT_ENCODING"] => string(13) "0x1F5:0x0:0x0"
["PHP_SELF"] => string(0) ""
["REQUEST_TIME_FLOAT"] => double(1458845731.5657)
["REQUEST_TIME"] => int(1458845731)
}
//$_POST
array(2) {
["genre"] => string(4) "punk"
["limit"] => string(2) "50"
}
We use the php-cgi
binary to setup the PHP environment. The php-cgi
binary uses environment variables and standard input to configure itself, we export these variables based on the information you provide in getRequests
.
getRequests
.You choose the CUSTOM type if you want the user to perform some arbitrary task that does not involve writing PHP code. For example the exercise could be to ask the user to download and install a program and then we could check that it is running.
This exercise type allows to simulate a real HTTP request to a PHP script.
Type | ExerciseType::CUSTOM() |
Interface | PhpSchool\PhpWorkshop\Exercise\CustomVerifyingExercise |
Methods to implement | verify |
This is where you perform your verification. The method needs to return an instance of PhpSchool\PhpWorkshop\Result\ResultInterface
. Depending on
whether you want a success or failure to be recorded it will be an instance of
PhpSchool\PhpWorkshop\Result\SuccessInterface
or
PhpSchool\PhpWorkshop\Result\FailureInterface
. Learn about results
here.
<?php
namespace PhpSchool\MyWorkshop\Exercise;
use PhpSchool\PhpWorkshop\Exercise\AbstractExercise;
use PhpSchool\PhpWorkshop\Exercise\CustomVerifyingExercise;
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
use PhpSchool\PhpWorkshop\Result\Success;
use PhpSchool\PhpWorkshop\Result\Failure;
class MyExercise extends AbstractExercise implements ExerciseInterface, CustomVerifyingExercise
{
...snip
/**
* @return ResultInterface
*/
public function verify()
{
if (//program is running) {
return new Success('My Program Check');
}
return new Failure('My Program Check', 'Program is running!');
}
/**
* @return ExerciseType
*/
public function getType()
{
return ExerciseType::CGI();
}
}
When a student runs the verify command your verify method will be invoked and the results will be displayed to the student!