Fork of FusionPBX but with LDAP kinda working
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

657 lines
16 KiB

<?php
/**
* This file provides the main QRCode class.
*
* The project is a rewrite from jQuery extension available at
* @link https://github.com/jeromeetienne/jquery-qrcode
*
* For a detailed description of QRCode and its features please check
* @link http://www.qrcode.com/
*
* QR Code is registered trademark of
* DENSO WAVE INCORPORATED
* http://www.denso-wave.com/qrcode/faqpatent-e.html
*
* All files in the package have the same license:
* http://opensource.org/licenses/BSD-2-Clause
*
* @copyright BSD2
* @author Maik Greubel <greubel@nkey.de>
*/
/**
* Import necessary dependencies
*/
require_once 'QR8bitByte.php';
require_once 'QRBitBuffer.php';
require_once 'QRRSBlock.php';
require_once 'QRUtil.php';
require_once 'QRCodeException.php';
/**
* This is the main class
*
* It provides the functionality to generate a QRCode bitmap
* out of appended data elements.
*
* @package phpQr
* @author Maik Greubel <greubel@nkey.de>
*/
class QRCode
{
/**
* Needed for padding
*
* @final
*
*/
const PAD0 = 0xec;
/**
* Needed for padding
*
* @final
*
*/
const PAD1 = 0x11;
/**
* The type number of qrcode
*
* @var int
*/
private $typeNumber;
/**
* Level of error correction
*
* @see QRErrorCorrectLevel
*
* @var int
*/
private $errorCorrectLevel;
/**
* Bitmap
*
* @var array
*/
private $modules;
/**
* Amount of modules in bitmap
*
* @var int
*/
private $moduleCount;
/**
* The data as array
*
* @var array
*/
private $dataCache;
/**
* All append data elements
*
* @var array
*/
private $dataList;
/**
* Create a new instance of QRCode
*
* @param int $typeNumber
* The type of QRCode
* @param int $errorCorrectLevel
* The error correction level
*/
public function __construct($typeNumber, $errorCorrectLevel)
{
$this->typeNumber = $typeNumber;
$this->errorCorrectLevel = $errorCorrectLevel;
$this->modules = null;
$this->moduleCount = 0;
$this->dataCache = null;
$this->dataList = array ();
}
/**
* This function is only needed for debugging purposes and returns the bitmap
* DONT USE THIS TO MANIPULATE THE BITMAP!
*
* @return array
*/
public function getModules()
{
return $this->modules;
}
/**
* Add a new data element to the QRCode
*
* @param string $data
*/
public function addData($data)
{
$newData = new QR8bitByte ( $data );
array_push ( $this->dataList, $newData );
$this->dataCache = null;
}
/**
* Returns whether a given bitmap entry is dark or not
*
* @param int $row
* The row in bitmap
* @param int $col
* The column in bitmap
*
* @throws QRCodeException
* @return true in case of its a dark bit, false otherwise
*/
public function isDark($row, $col)
{
if ($row < 0 || $this->moduleCount <= $row || $col < 0 || $this->moduleCount <= $col)
{
throw new QRCodeException ( "$row,$col" );
}
return $this->modules [$row] [$col];
}
/**
* Get the amount of modules in bitmap
*
* @return int
*/
public function getModuleCount()
{
return $this->moduleCount;
}
/**
* Generate the QRCode bitmap
*/
public function make()
{
if ($this->typeNumber < 1)
{
$typeNumber = 1;
for($typeNumber = 1; $typeNumber < 40; $typeNumber ++)
{
$rsBlocks = QRRSBlock::getInstance ()->getRSBlocks ( $typeNumber, $this->errorCorrectLevel );
$buffer = new QRBitBuffer ();
$totalDataCount = 0;
for($i = 0; $i < sizeof ( $rsBlocks ); $i ++)
{
$totalDataCount += $rsBlocks [$i]->getDataCount ();
}
for($i = 0; $i < sizeof ( $this->dataList ); $i ++)
{
$data = $this->dataList [$i];
assert ( $data instanceof QRByte );
$buffer->put ( $data->getMode (), 4 );
$buffer->put ( $data->getLength (), QRUtil::getInstance ()->getLengthInBits ( $data->getMode (), $typeNumber ) );
$data->write ( $buffer );
}
if ($buffer->getLengthInBits () <= $totalDataCount * 8)
break;
}
$this->typeNumber = $typeNumber;
}
$this->makeImpl ( false, $this->getBestMaskPattern () );
}
/**
* Generates the bitmap (really)
*
* @param boolean $test
* @param int $maskPattern
*/
private function makeImpl($test, $maskPattern)
{
$this->moduleCount = $this->typeNumber * 4 + 17;
$this->modules = QRUtil::getInstance ()->createEmptyArray ( $this->moduleCount );
for($row = 0; $row < $this->moduleCount; $row ++)
{
$this->modules [$row] = QRUtil::getInstance ()->createEmptyArray ( $this->moduleCount );
for($col = 0; $col < $this->moduleCount; $col ++)
{
$this->modules [$row] [$col] = null;
}
}
$this->setupPositionProbePattern ( 0, 0 );
$this->setupPositionProbePattern ( $this->moduleCount - 7, 0 );
$this->setupPositionProbePattern ( 0, $this->moduleCount - 7 );
$this->setupPositionAdjustPattern ();
$this->setupTimingPattern ();
$this->setupTypeInfo ( $test, $maskPattern );
if ($this->typeNumber >= 7)
{
$this->setTypeNumber ( $test );
}
if ($this->dataCache == null)
{
$this->dataCache = self::createData ( $this->typeNumber, $this->errorCorrectLevel, $this->dataList );
}
$this->mapData ( $this->dataCache, $maskPattern );
}
/**
* Add the position probes to the bitmap
*
* @param int $row
* @param int $col
*/
private function setupPositionProbePattern($row, $col)
{
for($r = - 1; $r <= 7; $r ++)
{
if ($row + $r <= - 1 || $this->moduleCount <= $row + $r)
continue;
for($c = - 1; $c <= 7; $c ++)
{
if ($col + $c <= - 1 || $this->moduleCount <= $col + $c)
continue;
if ((0 <= $r && $r <= 6 && ($c == 0 || $c == 6)) || (0 <= $c && $c <= 6 && ($r == 0 || $r == 6)) || (2 <= $r && $r <= 4 && 2 <= $c && $c <= 4))
{
$this->modules [$row + $r] [$col + $c] = true;
}
else
{
$this->modules [$row + $r] [$col + $c] = false;
}
}
}
}
/**
* Get the best mask pattern for this QRCode
*
* @return int
*/
private function getBestMaskPattern()
{
$minLostPoint = 0;
$pattern = 0;
for($i = 0; $i < 8; $i ++)
{
$this->makeImpl ( true, $i );
$lostPoint = QRUtil::getInstance ()->getLostPoint ( $this );
if ($i == 0 || $minLostPoint > $lostPoint)
{
$minLostPoint = $lostPoint;
$pattern = $i;
}
}
return $pattern;
}
/**
* Add the timing pattern to bitmap
*/
private function setupTimingPattern()
{
for($r = 8; $r < $this->moduleCount - 8; $r ++)
{
if ($this->modules [$r] [6] != null)
{
continue;
}
$this->modules [$r] [6] = ($r % 2 == 0);
}
for($c = 8; $c < $this->moduleCount - 8; $c ++)
{
if ($this->modules [6] [$c] != null)
{
continue;
}
$this->modules [6] [$c] = ($c % 2 == 0);
}
}
/**
* Add the position adjust pattern to bitmap
*/
private function setupPositionAdjustPattern()
{
$pos = QRUtil::getInstance ()->getPatternPosition ( $this->typeNumber );
for($i = 0; $i < sizeof ( $pos ); $i ++)
{
for($j = 0; $j < sizeof ( $pos ); $j ++)
{
$row = $pos [$i];
$col = $pos [$j];
if ($this->modules [$row] [$col] != null)
{
continue;
}
for($r = - 2; $r <= 2; $r ++)
{
for($c = - 2; $c <= 2; $c ++)
{
if ($r == - 2 || $r == 2 || $c == - 2 || $c == 2 || ($r == 0 && $c == 0))
{
$this->modules [$row + $r] [$col + $c] = true;
}
else
{
$this->modules [$row + $r] [$col + $c] = false;
}
}
}
}
}
}
/**
* Add the type number to bitmap
*
* @param boolean $test
*/
private function setTypeNumber($test)
{
$bits = QRUtil::getInstance ()->getBCHTypeNumber ( $this->typeNumber );
for($i = 0; $i < 18; $i ++)
{
$mod = (! $test && (($bits >> $i) & 1) == 1);
$this->modules [floor ( $i / 3 )] [$i % 3 + $this->moduleCount - 8 - 3] = $mod;
}
for($i = 0; $i < 18; $i ++)
{
$mod = (! $test && (($bits >> $i) & 1) == 1);
$this->modules [$i % 3 + $this->moduleCount - 8 - 3] [floor ( $i / 3 )] = $mod;
}
}
/**
* Add the type info to bitmap
*
* @param boolean $test
* @param int $maskPattern
*/
private function setupTypeInfo($test, $maskPattern)
{
$data = ($this->errorCorrectLevel << 3) | $maskPattern;
$bits = QRUtil::getInstance ()->getBCHTypeInfo ( $data );
// vertical
for($i = 0; $i < 15; $i ++)
{
$mod = (! $test && (($bits >> $i) & 1) == 1);
if ($i < 6)
{
$this->modules [$i] [8] = $mod;
}
else if ($i < 8)
{
$this->modules [$i + 1] [8] = $mod;
}
else
{
$this->modules [$this->moduleCount - 15 + $i] [8] = $mod;
}
}
// horizontal
for($i = 0; $i < 15; $i ++)
{
$mod = (! $test && (($bits >> $i) & 1) == 1);
if ($i < 8)
{
$this->modules [8] [$this->moduleCount - $i - 1] = $mod;
}
else if ($i < 9)
{
$this->modules [8] [15 - $i - 1 + 1] = $mod;
}
else
{
$this->modules [8] [15 - $i - 1] = $mod;
}
}
// fixed module
$this->modules [$this->moduleCount - 8] [8] = (! $test);
}
/**
* Add the data to bitmap
*
* @param array $data
* @param int $maskPattern
*/
private function mapData($data, $maskPattern)
{
$inc = - 1;
$row = $this->moduleCount - 1;
$bitIndex = 7;
$byteIndex = 0;
for($col = $this->moduleCount - 1; $col > 0; $col -= 2)
{
if ($col == 6)
$col --;
while ( true )
{
for($c = 0; $c < 2; $c ++)
{
if ($this->modules [$row] [$col - $c] === null)
{
$dark = false;
if ($byteIndex < sizeof ( $data ))
{
$dark = ((($data [$byteIndex] >> $bitIndex) & 1) == 1);
}
$mask = QRUtil::getInstance ()->getMask ( $maskPattern, $row, $col - $c );
if ($mask)
$dark = ! $dark;
$this->modules [$row] [$col - $c] = $dark;
$bitIndex --;
if ($bitIndex == - 1)
{
$byteIndex ++;
$bitIndex = 7;
}
}
}
$row += $inc;
if ($row < 0 || $this->moduleCount <= $row)
{
$row -= $inc;
$inc = - $inc;
break;
}
}
}
}
/**
* Create a bitmap out of all append data elements
*
* @param int $typeNumber
* @param int $errorCorrectLevel
* @param array $dataList
*
* @throws QRCodeException
*
* @return array
*/
private function createData($typeNumber, $errorCorrectLevel, $dataList)
{
$rsBlocks = QRRSBlock::getInstance ()->getRSBlocks ( $typeNumber, $errorCorrectLevel );
$buffer = new QRBitBuffer ();
for($i = 0; $i < sizeof ( $dataList ); $i ++)
{
$data = $dataList [$i];
assert ( $data instanceof QRByte );
$buffer->put ( $data->getMode (), 4 );
$buffer->put ( $data->getLength (), QRUtil::getInstance ()->getLengthInBits ( $data->getMode (), $typeNumber ) );
$data->write ( $buffer );
}
// calc num max data
$totalDataCount = 0;
for($i = 0; $i < sizeof ( $rsBlocks ); $i ++)
{
$totalDataCount += $rsBlocks [$i]->getDataCount ();
}
if ($buffer->getLengthInBits () > $totalDataCount * 8)
{
throw new QRCodeException ( "code length overflow (" . $buffer->getLengthInBits () . " > " . ($totalDataCount * 8) . ")" );
}
// end code
if ($buffer->getLengthInBits () + 4 <= $totalDataCount * 8)
{
$buffer->put ( 0, 4 );
}
// padding
while ( $buffer->getLengthInBits () % 8 != 0 )
{
$buffer->putBit ( false );
}
// padding
while ( true )
{
if ($buffer->getLengthInBits () >= $totalDataCount * 8)
{
break;
}
$buffer->put ( QRCode::PAD0, 8 );
if ($buffer->getLengthInBits () >= $totalDataCount * 8)
{
break;
}
$buffer->put ( QRCode::PAD1, 8 );
}
return $this->createBytes ( $buffer, $rsBlocks );
}
/**
* Create bitmap out of the bit buffer using reed solomon blocks
*
* @param QRBitBuffer $buffer
* @param array $rsBlocks
* @return array
*/
public function createBytes(QRBitBuffer $buffer, $rsBlocks)
{
$offset = 0;
$maxDcCount = 0;
$maxEcCount = 0;
$dcdata = QRUtil::getInstance ()->createEmptyArray ( sizeof ( $rsBlocks ) );
$ecdata = QRUtil::getInstance ()->createEmptyArray ( sizeof ( $rsBlocks ) );
for($r = 0; $r < sizeof ( $rsBlocks ); $r ++)
{
$dcCount = $rsBlocks [$r]->getDataCount ();
$ecCount = $rsBlocks [$r]->getTotalCount () - $dcCount;
$maxDcCount = max ( array (
$maxDcCount,
$dcCount
) );
$maxEcCount = max ( array (
$maxEcCount,
$ecCount
) );
$dcdata [$r] = QRUtil::getInstance ()->createEmptyArray ( $dcCount );
for($i = 0; $i < sizeof ( $dcdata [$r] ); $i ++)
{
$dcdata [$r] [$i] = 0xff & $buffer->getAt ( $i + $offset );
}
$offset += $dcCount;
$rsPoly = QRUtil::getInstance ()->getErrorCorrectPolynominal ( $ecCount );
$rawPoly = new QRPolynominal ( $dcdata [$r], $rsPoly->getLength () - 1 );
$modPoly = $rawPoly->mod ( $rsPoly );
$ecdata [$r] = QRUtil::getInstance ()->createEmptyArray ( $rsPoly->getLength () - 1 );
for($i = 0; $i < sizeof ( $ecdata [$r] ); $i ++)
{
$modIndex = $i + $modPoly->getLength () - sizeof ( $ecdata [$r] );
$ecdata [$r] [$i] = ($modIndex >= 0) ? $modPoly->get ( $modIndex ) : 0;
}
}
$totalCodeCount = 0;
for($i = 0; $i < sizeof ( $rsBlocks ); $i ++)
{
$totalCodeCount += $rsBlocks [$i]->getTotalCount ();
}
$data = QRUtil::getInstance ()->createEmptyArray ( $totalCodeCount );
$index = 0;
for($i = 0; $i < $maxDcCount; $i ++)
{
for($r = 0; $r < sizeof ( $rsBlocks ); $r ++)
{
if ($i < sizeof ( $dcdata [$r] ))
{
$data [$index ++] = $dcdata [$r] [$i];
}
}
}
for($i = 0; $i < $maxEcCount; $i ++)
{
for($r = 0; $r < sizeof ( $rsBlocks ); $r ++)
{
if ($i < sizeof ( $ecdata [$r] ))
{
$data [$index ++] = $ecdata [$r] [$i];
}
}
}
return $data;
}
}
//yea will need to inspect this for the ldap qr code