Вход Регистрация
Файл: PROFIWM.COM/modules/servis/qr/qrinput.php
Строк: 456
<?php
/*
 * PHP QR Code encoder
 *
 * Input encoding class
 *
 * Based on libqrencode C library distributed under LGPL 2.1
 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
 *
 * PHP QR Code is distributed under LGPL 3
 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */
 
    
define('STRUCTURE_HEADER_BITS',  20);
    
define('MAX_STRUCTURED_SYMBOLS', 16);

    class 
QRinputItem {
    
        public 
$mode;
        public 
$size;
        public 
$data;
        public 
$bstream;

        public function 
__construct($mode, $size, $data, $bstream = null) 
        {
            
$setData = array_slice($data, 0, $size);
            
            if (
count($setData) < $size) {
                
$setData = array_merge($setData, array_fill(0,$size-count($setData),0));
            }
        
            if(!
QRinput::check($mode, $size, $setData)) {
                throw new 
Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData));
                return 
null;
            }
            
            
$this->mode = $mode;
            
$this->size = $size;
            
$this->data = $setData;
            
$this->bstream = $bstream;
        }
        
        
//----------------------------------------------------------------------
        
public function encodeModeNum($version)
        {
            try {
            
                
$words = (int)($this->size / 3);
                
$bs = new QRbitstream();
                
                
$val = 0x1;
                
$bs->appendNum(4, $val);
                
$bs->appendNum(QRspec::lengthIndicator(QR_MODE_NUM, $version), $this->size);

                for(
$i=0; $i<$words; $i++) {
                    
$val  = (ord($this->data[$i*3  ]) - ord('0')) * 100;
                    
$val += (ord($this->data[$i*3+1]) - ord('0')) * 10;
                    
$val += (ord($this->data[$i*3+2]) - ord('0'));
                    
$bs->appendNum(10, $val);
                }

                if(
$this->size - $words * 3 == 1) {
                    
$val = ord($this->data[$words*3]) - ord('0');
                    
$bs->appendNum(4, $val);
                } else if(
$this->size - $words * 3 == 2) {
                    
$val  = (ord($this->data[$words*3  ]) - ord('0')) * 10;
                    
$val += (ord($this->data[$words*3+1]) - ord('0'));
                    
$bs->appendNum(7, $val);
                }

                
$this->bstream = $bs;
                return 
0;
                
            } catch (
Exception $e) {
                return -
1;
            }
        }
        
        
//----------------------------------------------------------------------
        
public function encodeModeAn($version)
        {
            try {
                
$words = (int)($this->size / 2);
                
$bs = new QRbitstream();
                
                
$bs->appendNum(4, 0x02);
                
$bs->appendNum(QRspec::lengthIndicator(QR_MODE_AN, $version), $this->size);

                for(
$i=0; $i<$words; $i++) {
                    
$val  = (int)QRinput::lookAnTable(ord($this->data[$i*2  ])) * 45;
                    
$val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1]));

                    
$bs->appendNum(11, $val);
                }

                if(
$this->size & 1) {
                    
$val = QRinput::lookAnTable(ord($this->data[$words * 2]));
                    
$bs->appendNum(6, $val);
                }
        
                
$this->bstream = $bs;
                return 
0;
            
            } catch (
Exception $e) {
                return -
1;
            }
        }
        
        
//----------------------------------------------------------------------
        
public function encodeMode8($version)
        {
            try {
                
$bs = new QRbitstream();

                
$bs->appendNum(4, 0x4);
                
$bs->appendNum(QRspec::lengthIndicator(QR_MODE_8, $version), $this->size);

                for(
$i=0; $i<$this->size; $i++) {
                    
$bs->appendNum(8, ord($this->data[$i]));
                }

                
$this->bstream = $bs;
                return 
0;
            
            } catch (
Exception $e) {
                return -
1;
            }
        }
        
        
//----------------------------------------------------------------------
        
public function encodeModeKanji($version)
        {
            try {

                
$bs = new QRbitrtream();
                
                
$bs->appendNum(4, 0x8);
                
$bs->appendNum(QRspec::lengthIndicator(QR_MODE_KANJI, $version), (int)($this->size / 2));

                for(
$i=0; $i<$this->size; $i+=2) {
                    
$val = (ord($this->data[$i]) << 8) | ord($this->data[$i+1]);
                    if(
$val <= 0x9ffc) {
                        
$val -= 0x8140;
                    } else {
                        
$val -= 0xc140;
                    }
                    
                    
$h = ($val >> 8) * 0xc0;
                    
$val = ($val & 0xff) + $h;

                    
$bs->appendNum(13, $val);
                }

                
$this->bstream = $bs;
                return 
0;
            
            } catch (
Exception $e) {
                return -
1;
            }
        }

        
//----------------------------------------------------------------------
        
public function encodeModeStructure()
        {
            try {
                
$bs =  new QRbitstream();
                
                
$bs->appendNum(4, 0x03);
                
$bs->appendNum(4, ord($this->data[1]) - 1);
                
$bs->appendNum(4, ord($this->data[0]) - 1);
                
$bs->appendNum(8, ord($this->data[2]));

                
$this->bstream = $bs;
                return 
0;
            
            } catch (
Exception $e) {
                return -
1;
            }
        }
        
        
//----------------------------------------------------------------------
        
public function estimateBitStreamSizeOfEntry($version)
        {
            
$bits = 0;

            if(
$version == 0) 
                
$version = 1;

            switch(
$this->mode) {
                case 
QR_MODE_NUM:        $bits = QRinput::estimateBitsModeNum($this->size);    break;
                case 
QR_MODE_AN:        $bits = QRinput::estimateBitsModeAn($this->size);    break;
                case 
QR_MODE_8:            $bits = QRinput::estimateBitsMode8($this->size);    break;
                case 
QR_MODE_KANJI:        $bits = QRinput::estimateBitsModeKanji($this->size);break;
                case 
QR_MODE_STRUCTURE:    return STRUCTURE_HEADER_BITS;            
                default:
                    return 
0;
            }

            
$l = QRspec::lengthIndicator($this->mode, $version);
            
$m = 1 << $l;
            
$num = (int)(($this->size + $m - 1) / $m);

            
$bits += $num * (4 + $l);

            return 
$bits;
        }
        
        
//----------------------------------------------------------------------
        
public function encodeBitStream($version)
        {
            try {
            
                unset(
$this->bstream);
                
$words = QRspec::maximumWords($this->mode, $version);
                
                if(
$this->size > $words) {
                
                    
$st1 = new QRinputItem($this->mode, $words, $this->data);
                    
$st2 = new QRinputItem($this->mode, $this->size - $words, array_slice($this->data, $words));

                    
$st1->encodeBitStream($version);
                    
$st2->encodeBitStream($version);
                    
                    
$this->bstream = new QRbitstream();
                    
$this->bstream->append($st1->bstream);
                    
$this->bstream->append($st2->bstream);
                    
                    unset(
$st1);
                    unset(
$st2);
                    
                } else {
                    
                    
$ret = 0;
                    
                    switch(
$this->mode) {
                        case 
QR_MODE_NUM:        $ret = $this->encodeModeNum($version);    break;
                        case 
QR_MODE_AN:        $ret = $this->encodeModeAn($version);    break;
                        case 
QR_MODE_8:            $ret = $this->encodeMode8($version);    break;
                        case 
QR_MODE_KANJI:        $ret = $this->encodeModeKanji($version);break;
                        case 
QR_MODE_STRUCTURE:    $ret = $this->encodeModeStructure();    break;
                        
                        default:
                            break;
                    }
                    
                    if(
$ret < 0)
                        return -
1;
                }

                return 
$this->bstream->size();
            
            } catch (
Exception $e) {
                return -
1;
            }
        }
    };
    
    
//##########################################################################

    
class QRinput {

        public 
$items;
        
        private 
$version;
        private 
$level;
        
        
//----------------------------------------------------------------------
        
public function __construct($version = 0, $level = QR_ECLEVEL_L)
        {
            if (
$version < 0 || $version > QRSPEC_VERSION_MAX || $level > QR_ECLEVEL_H) {
                throw new 
Exception('Invalid version no');
                return 
NULL;
            }
            
            
$this->version = $version;
            
$this->level = $level;
        }
        
        
//----------------------------------------------------------------------
        
public function getVersion()
        {
            return 
$this->version;
        }
        
        
//----------------------------------------------------------------------
        
public function setVersion($version)
        {
            if(
$version < 0 || $version > QRSPEC_VERSION_MAX) {
                throw new 
Exception('Invalid version no');
                return -
1;
            }

            
$this->version = $version;

            return 
0;
        }
        
        
//----------------------------------------------------------------------
        
public function getErrorCorrectionLevel()
        {
            return 
$this->level;
        }

        
//----------------------------------------------------------------------
        
public function setErrorCorrectionLevel($level)
        {
            if(
$level > QR_ECLEVEL_H) {
                throw new 
Exception('Invalid ECLEVEL');
                return -
1;
            }

            
$this->level = $level;

            return 
0;
        }
        
        
//----------------------------------------------------------------------
        
public function appendEntry(QRinputItem $entry)
        {
            
$this->items[] = $entry;
        }
        
        
//----------------------------------------------------------------------
        
public function append($mode, $size, $data)
        {
            try {
                
$entry = new QRinputItem($mode, $size, $data);
                
$this->items[] = $entry;
                return 
0;
            } catch (
Exception $e) {
                return -
1;
            }
        }
        
        
//----------------------------------------------------------------------
        
        
public function insertStructuredAppendHeader($size, $index, $parity)
        {
            if( 
$size > MAX_STRUCTURED_SYMBOLS ) {
                throw new 
Exception('insertStructuredAppendHeader wrong size');
            }
            
            if( 
$index <= 0 || $index > MAX_STRUCTURED_SYMBOLS ) {
                throw new 
Exception('insertStructuredAppendHeader wrong index');
            }

            
$buf = array($size, $index, $parity);
            
            try {
                
$entry = new QRinputItem(QR_MODE_STRUCTURE, 3, buf);
                
array_unshift($this->items, $entry);
                return 
0;
            } catch (
Exception $e) {
                return -
1;
            }
        }

        
//----------------------------------------------------------------------
        
public function calcParity()
        {
            
$parity = 0;
            
            foreach(
$this->items as $item) {
                if(
$item->mode != QR_MODE_STRUCTURE) {
                    for(
$i=$item->size-1; $i>=0; $i--) {
                        
$parity ^= $item->data[$i];
                    }
                }
            }

            return 
$parity;
        }
        
        
//----------------------------------------------------------------------
        
public static function checkModeNum($size, $data)
        {
            for(
$i=0; $i<$size; $i++) {
                if((
ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))){
                    return 
false;
                }
            }

            return 
true;
        }

        
//----------------------------------------------------------------------
        
public static function estimateBitsModeNum($size)
        {
            
$w = (int)$size / 3;
            
$bits = $w * 10;
            
            switch(
$size - $w * 3) {
                case 
1:
                    
$bits += 4;
                    break;
                case 
2:
                    
$bits += 7;
                    break;
                default:
                    break;
            }

            return 
$bits;
        }
        
        
//----------------------------------------------------------------------
        
public static $anTable = array(
            -
1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -
1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            
36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,
             
0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 44, -1, -1, -1, -1, -1,
            -
1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
            
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
            -
1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -
1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
        
);
        
        
//----------------------------------------------------------------------
        
public static function lookAnTable($c)
        {
            return ((
$c > 127)?-1:self::$anTable[$c]);
        }
        
        
//----------------------------------------------------------------------
        
public static function checkModeAn($size, $data)
        {
            for(
$i=0; $i<$size; $i++) {
                if (
self::lookAnTable(ord($data[$i])) == -1) {
                    return 
false;
                }
            }

            return 
true;
        }
        
        
//----------------------------------------------------------------------
        
public static function estimateBitsModeAn($size)
        {
            
$w = (int)($size / 2);
            
$bits = $w * 11;
            
            if(
$size & 1) {
                
$bits += 6;
            }

            return 
$bits;
        }
    
        
//----------------------------------------------------------------------
        
public static function estimateBitsMode8($size)
        {
            return 
$size * 8;
        }
        
        
//----------------------------------------------------------------------
        
public function estimateBitsModeKanji($size)
        {
            return (int)((
$size / 2) * 13);
        }
        
        
//----------------------------------------------------------------------
        
public static function checkModeKanji($size, $data)
        {
            if(
$size & 1)
                return 
false;

            for(
$i=0; $i<$size; $i+=2) {
                
$val = (ord($data[$i]) << 8) | ord($data[$i+1]);
                if( 
$val < 0x8140 
                
|| ($val > 0x9ffc && $val < 0xe040) 
                || 
$val > 0xebbf) {
                    return 
false;
                }
            }

            return 
true;
        }

        
/***********************************************************************
         * Validation
         **********************************************************************/

        
public static function check($mode, $size, $data)
        {
            if(
$size <= 0) 
                return 
false;

            switch(
$mode) {
                case 
QR_MODE_NUM:       return self::checkModeNum($size, $data);   break;
                case 
QR_MODE_AN:        return self::checkModeAn($size, $data);    break;
                case 
QR_MODE_KANJI:     return self::checkModeKanji($size, $data); break;
                case 
QR_MODE_8:         return true; break;
                case 
QR_MODE_STRUCTURE: return true; break;
                
                default:
                    break;
            }

            return 
false;
        }
        
        
        
//----------------------------------------------------------------------
        
public function estimateBitStreamSize($version)
        {
            
$bits = 0;

            foreach(
$this->items as $item) {
                
$bits += $item->estimateBitStreamSizeOfEntry($version);
            }

            return 
$bits;
        }
        
        
//----------------------------------------------------------------------
        
public function estimateVersion()
        {
            
$version = 0;
            
$prev = 0;
            do {
                
$prev = $version;
                
$bits = $this->estimateBitStreamSize($prev);
                
$version = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
                if (
$version < 0) {
                    return -
1;
                }
            } while (
$version > $prev);

            return 
$version;
        }
        
        
//----------------------------------------------------------------------
        
public static function lengthOfCode($mode, $version, $bits)
        {
            
$payload = $bits - 4 - QRspec::lengthIndicator($mode, $version);
            switch(
$mode) {
                case 
QR_MODE_NUM:
                    
$chunks = (int)($payload / 10);
                    
$remain = $payload - $chunks * 10;
                    
$size = $chunks * 3;
                    if(
$remain >= 7) {
                        
$size += 2;
                    } else if(
$remain >= 4) {
                        
$size += 1;
                    }
                    break;
                case 
QR_MODE_AN:
                    
$chunks = (int)($payload / 11);
                    
$remain = $payload - $chunks * 11;
                    
$size = $chunks * 2;
                    if(
$remain >= 6) 
                        
$size++;
                    break;
                case 
QR_MODE_8:
                    
$size = (int)($payload / 8);
                    break;
                case 
QR_MODE_KANJI:
                    
$size = (int)(($payload / 13) * 2);
                    break;
                case 
QR_MODE_STRUCTURE:
                    
$size = (int)($payload / 8);
                    break;
                default:
                    
$size = 0;
                    break;
            }
            
            
$maxsize = QRspec::maximumWords($mode, $version);
            if(
$size < 0) $size = 0;
            if(
$size > $maxsize) $size = $maxsize;

            return 
$size;
        }
        
        
//----------------------------------------------------------------------
        
public function createBitStream()
        {
            
$total = 0;

            foreach(
$this->items as $item) {
                
$bits = $item->encodeBitStream($this->version);
                
                if(
$bits < 0) 
                    return -
1;
                    
                
$total += $bits;
            }

            return 
$total;
        }
        
        
//----------------------------------------------------------------------
        
public function convertData()
        {
            
$ver = $this->estimateVersion();
            if(
$ver > $this->getVersion()) {
                
$this->setVersion($ver);
            }

            for(;;) {
                
$bits = $this->createBitStream();
                
                if(
$bits < 0) 
                    return -
1;
                    
                
$ver = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
                if(
$ver < 0) {
                    throw new 
Exception('WRONG VERSION');
                    return -
1;
                } else if(
$ver > $this->getVersion()) {
                    
$this->setVersion($ver);
                } else {
                    break;
                }
            }

            return 
0;
        }
        
        
//----------------------------------------------------------------------
        
public function appendPaddingBit(&$bstream)
        {
            
$bits = $bstream->size();
            
$maxwords = QRspec::getDataLength($this->version, $this->level);
            
$maxbits = $maxwords * 8;

            if (
$maxbits == $bits) {
                return 
0;
            }

            if (
$maxbits - $bits < 5) {
                return 
$bstream->appendNum($maxbits - $bits, 0);
            }

            
$bits += 4;
            
$words = (int)(($bits + 7) / 8);

            
$padding = new QRbitstream();
            
$ret = $padding->appendNum($words * 8 - $bits + 4, 0);
            
            if(
$ret < 0) 
                return 
$ret;

            
$padlen = $maxwords - $words;
            
            if(
$padlen > 0) {
                
                
$padbuf = array();
                for(
$i=0; $i<$padlen; $i++) {
                    
$padbuf[$i] = ($i&1)?0x11:0xec;
                }
                
                
$ret = $padding->appendBytes($padlen, $padbuf);
                
                if(
$ret < 0)
                    return 
$ret;
                
            }

            
$ret = $bstream->append($padding);
            
            return 
$ret;
        }

        
//----------------------------------------------------------------------
        
public function mergeBitStream()
        {
            if(
$this->convertData() < 0) {
                return 
null;
            }

            
$bstream = new QRbitstream();
            
            foreach(
$this->items as $item) {
                
$ret = $bstream->append($item->bstream);
                if(
$ret < 0) {
                    return 
null;
                }
            }

            return 
$bstream;
        }

        
//----------------------------------------------------------------------
        
public function getBitStream()
        {

            
$bstream = $this->mergeBitStream();
            
            if(
$bstream == null) {
                return 
null;
            }
            
            
$ret = $this->appendPaddingBit($bstream);
            if(
$ret < 0) {
                return 
null;
            }

            return 
$bstream;
        }
        
        
//----------------------------------------------------------------------
        
public function getByteStream()
        {
            
$bstream = $this->getBitStream();
            if(
$bstream == null) {
                return 
null;
            }
            
            return 
$bstream->toByte();
        }
    }
Онлайн: 2
Реклама