* */ class taoQtiCommon_helpers_Utils { /** * Amount of bytes to read for each * read instructions while reading a * JSON payload. The current value is * 262,144 bytes -> 256 kbytes * * @var integer */ const JSON_PAYLOAD_CHUNK_SIZE = 262144; /** * Reads a JSON Payload from 'php://input' and decodes it * as an associative array * * @return boolean|array An associative array representing the JSON payload or false if an error occurs. */ static public function readJsonPayload() { $fp = fopen('php://input', 'rb'); if ($fp === false) { return false; } $payload = ''; while (feof($fp) !== true) { $payload .= fread($fp, self::JSON_PAYLOAD_CHUNK_SIZE); } @fclose($fp); return @json_decode($payload, true); } /** * Marshall a QTI File datatype into a binary string. The resulting binary string constitution * is the following: * * * The length of the file name, unsigned short. * * The file name, string. * * The length of the mime type, unsigned short. * * The mime type, string. * * The binary content of the file, string. * * @param File $file * @return string */ static public function qtiFileToString(QtiFile $file) { $string = ''; $filename = $file->getFilename(); $mimetype = $file->getMimeType(); $filenameLen = strlen($filename); $mimetypeLen = strlen($mimetype); $string .= pack('S', $filenameLen); $string .= $filename; $string .= pack('S', $mimetypeLen); $string .= $mimetype; // Avoid invalid data for serialize // (This could make me cry...) $string .= $file->getData(); return $string; } /** * Whether or not a given QTI Variable contains the QTI Placeholder File. * * @param Variable $variable * @return boolean */ static public function isQtiFilePlaceHolder(Variable $variable) { $correctBaseType = $variable->getBaseType() === BaseType::FILE; $correctCardinality = $variable->getCardinality() === Cardinality::SINGLE; if ($correctBaseType === true && $correctCardinality === true) { $value = $variable->getValue(); $notNull = $value !== null; $mime = taoQtiCommon_helpers_PciJsonMarshaller::FILE_PLACEHOLDER_MIMETYPE; if ($notNull === true && $value->getMimeType() === $mime) { return true; } } return false; } /** * Whether or not a given QTI Variable contains a QTI File value. * * @param Variable $variable * @param boolean $considerNull Whether or not to consider File variables containing NULL variables. * @return boolean */ static public function isQtiFile(Variable $variable, $considerNull = true) { $correctBaseType = $variable->getBaseType() === BaseType::FILE; $correctCardinality = $variable->getCardinality() === Cardinality::SINGLE; $nullConsideration = ($considerNull === true) ? true : $variable->getValue() !== null; return $correctBaseType === true && $correctCardinality === true && $nullConsideration === true; } /** * Transform a TAO serialized result value to its QtiDatatype equivalent. * * This method transforms a TAO serialized result $value to a the equivalent QtiDatatype depending * on result's $cardinality and $baseType. * * Note: at the present time, this implementation only supports 'single', 'multiple', and 'ordered' cardinality in conjunction * with the 'identifier', 'boolean', 'pair' or 'directedPair' baseType. * * @param string $cardinality i.e. 'ordered', 'multiple' or 'single'. * @param string $basetype i.e. 'identifier' * @param string $value A TAO serialized result value e.g. '' * @return mixed A QtiDatatype object or null in case of no possibility to transform $value in the appropriate target $cardinality and $basetype. */ static public function toQtiDatatype($cardinality, $basetype, $value) { // @todo support all baseTypes $datatype = null; if (is_string($value) && empty($value) === false && $cardinality !== 'record' && ($basetype === 'identifier' || $basetype === 'pair' || $basetype === 'directedPair' || $basetype === 'boolean')) { if ($cardinality !== 'simple') { $value = trim($value, "<>[]"); $value = explode(';', $value); } else { $value = array($value); } if (count($value) === 1 && empty($value[0]) === true) { $value = array(); } $value = array_map( function($val) { return trim($val); }, $value ); $qtiBasetype = BaseType::getConstantByName($basetype); $datatype = ($cardinality === 'ordered') ? new OrderedContainer($qtiBasetype) : new MultipleContainer($qtiBasetype); foreach ($value as $val) { try { switch ($basetype) { case 'identifier': $datatype[] = new QtiIdentifier($val); break; case 'pair': $pair = explode("\x20", $val); if (count($pair) === 2) { $datatype[] = new QtiPair($pair[0], $pair[1]); } break; case 'directedPair': $pair = explode("\x20", $val); if (count($pair) === 2) { $datatype[] = new QtiDirectedPair($pair[0], $pair[1]); } break; case 'boolean': if ($val === 'true') { $datatype[] = new QtiBoolean(true); } elseif ($val === 'false') { $datatype[] = new QtiBoolean(false); } else { $datatype[] = new QtiBoolean($val); } break; } } catch (InvalidArgumentException $e) { $datatype = null; break; } } $datatype = ($cardinality === 'single') ? (isset($datatype[0]) ? $datatype[0] : null) : $datatype; } return $datatype; } }