Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Загадка Flash - PHP Serializer Class, не правильно работает unserialize (http://www.flasher.ru/forum/showthread.php?t=186623)

rolling_kz 06.11.2012 14:57

Загадка Flash - PHP Serializer Class, не правильно работает unserialize
 
Здраствуйте,

Для передачи данных между PHP и Flex мы приспособились использовать сериализированные объекты.
Очень удобно. На стороне PHP - serialize/unserialize - стандартные функции. А в AS3 используем класс некоего Alessandro Crugnola: http://sourceforge.net/projects/serializerclass/

Но вот недавно обнаружили толи баг то ли фичу:
После выполнения:
Код AS3:

var obj:Object = {aaa:{af:11}, bbb:{bf:22} };
var tmpStr:String = Serializer.serialize(obj);
var obj2:* = Serializer.unserialize(tmpStr);

obj2 не соответствует obj:
Код AS3:

obj2        Object (@5c2fad9)        
        aaa        Object (@5c2fe39)       
                af        11 [0xb]       
        undefined        undefined


В случае простого линейного объекта все работает.
При этом ясно что косячит именно unserialize.
т.к. tmpStr иммет правильный вид:
Код AS3:

tmpStr        "O:8:"stdClass":2:{s:3:"aaa";O:8:"stdClass":1:{s:2:"af";i:11;}s:3:"bbb";O:8:"stdClass":1:{s:2:"bf";i:22;}}"


Может кто-нибудь помочь. По моему в коде класса сериализатора баг.

Алгорит класса Serializer достаточно сложный, не могу сам найти где там поправить.

Спасибо

GBee 06.11.2012 15:27

может спросить у Alessandro Crugnola?
я лично вижу странность, что перед пропертей bbb в tmpStr нет ни запятой, ни точки с запятой. Хотя может это формат такой.

rolling_kz 06.11.2012 17:06

Код старый, автор вряд ли ответит.

Что касается запятой, то для меня этот формат пока загадка. Принци его понять не могу.

КорДум 06.11.2012 17:15

Так сериализуются пхп-объекты. О - обджект, а - массив, s - строка и так далее.
http://php.net/manual/ru/function.serialize.php

GBee 06.11.2012 17:18

Да формат примерно понятный, но странный
Цитата:

"O:8:"stdClass":2:{s:3:"aaa";O:8:"stdClass":1:{s:2:"af";i:11;}s:3:"bbb";O:8:"stdClass":1:{s:2:"bf";i:22;}}"
О - объект
8 - пока не понял, по идее размер.
stdClass - класс
2 - кол-во полей
s - строка
3 - размер ее
"ааа" - название поля
i - integer

КорДум 06.11.2012 17:21

8 - длина значения или ключа. В данном случае ключа.
2 - длина строки ключа
11 - значение числа (вроде как)

rolling_kz 06.11.2012 17:44

Спасибо за ссылку, по ней я понял насколько сложный формат.

А почему класс не пашет?
как только ассоциативный массив внутри глючить начинает.

КорДум 06.11.2012 18:39

Это нужно спросить у создателя. А вообще, если глючит, проще посидеть часок и наваять свой алгоритм десериализации конечными автоматами. И сериализации, тщательно изучив формат. Там не так много объектов, чтобы пугаться.

rolling_kz 06.11.2012 19:16

у создателя спросил - молчит.

я не совсем гуру. уйдет очень много времени.
спросил вдруг в в этом алгоритме кто-то заметит где ошибка:

Код AS3:

/*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @license FREEWARE
* @copyright (c) 2003 sephiroth.it
*
* SerializerClass is the base class for retreiving complex data type
* from and to PHP pages using the built-in serializer/unserializer
* php functions
* Thanks to Rainer Becker [rainer.becker@pixelmotive.de] for the string bug fixing
* Gavril Tarasoff for PHP5 stdObject addition
*
* @project : serializer
* @file :    Serializer
* @author :  Alessandro Crugnola- alessandro@sephiroth.it/ www.sephiroth.it
* @version  $Id: Serializer.as,v 1.19 2006/04/19 08:37:45 sephiroth_tmm Exp $
*
*/

package
{
        import mx.core.*;
        use namespace mx_internal;
 
        /**
        * Serializer enable you to pass and receive complex data type from/to PHP/Flash using the native PHP functions serialize and unserialize.
        * Flash received data will be a native Flash object too.
        *
        * @author alessandro crugnola (alessandro@sephiroth.it)
        * @version 3.0.0
        * @url http://www.sephiroth.it/test/unserializer
        */
       
        public class Serializer extends Object
        {
                public static const version:String = "3.0.0";
 
                mx_internal static var c:uint;
                mx_internal static var pattern:RegExp = /[A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2} \+|\-\d{4}/g
 
                /**
                * Serialize an input data into a PHP readable string
                * which can be send through get or post and deserialized
                * into the starting object
                *
                * @param data
                * @return the serialized string
                * @example
                *
                * <pre>
                * var o:Object = {first:1, second:[1,2,3,4]};
                * var result:String = Serializer.serialize(o);
                * </pre>
                */

                public static function serialize(data:*):String
                {
                        var s:String;
                        var tmp:Array = new Array();
                        var i:int = 0;
                        var key:String;
 
                        if(data is Boolean){
                                s = "b:"+uint(data)+";";
                        } else if(data is int){
                                s = "i:"+data.toString()+";";
                        } else if(data is Number){
                                s = "d:"+data.toString()+";";
                        } else if(data is String){
                                s = "s:"+Serializer.stringLength(data)+":\""+data+"\";"
                        } else if(data is Date){
                                s = "s:" + data.toString().length + ":\"" + data + "\";"
                        } else if(data is Object){
                                for(key in data){
                                        tmp.push(Serializer.serialize(key));
                                        tmp.push(Serializer.serialize(data[key]));
                                        i += 1;
                                }
                                s = "O:8:\"stdClass\":" + i + ":{" + tmp.join("") + "}";
                        } else if(data is Array){
                                for(key in data){
                                        tmp.push(Serializer.serialize(i))
                                        tmp.push(Serializer.serialize(data[key]))
                                        i += 1
                                }
                                s = "a:"+i+":{"+ tmp.join("") + "}";
                        } else if(data == null || data == undefined){
                                s = "N;";
                        } else {
                                s = "i:0;"
                        }
                        return s;
                }
 
                /**
                * unserialize PHP serialized string into a
                * readable Flash object
                * @param data serialized string
                * @return type depends on the content of serialized string
                *
                * @example
                *  <pre>
                *        import flash.net.*;
                *        import org.sepy.io.Serializer;
                *
                *        private var req:URLRequest;
                *        private var loader:URLLoader;
                *
                *        private function init():void
                *        {
                *                req = new URLRequest("http://localhost/serializer/unserializer.php?getvalue");
                *                loader = new URLLoader(req);
                *                loader.addEventListener(Event.COMPLETE, handler);
                *                loader.dataFormat = URLLoaderDataFormat.VARIABLES;
                *                loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, handler);
                *        }
                *       
                *        private function handler(e:Event):void
                *        {
                *                if(e.type == Event.COMPLETE)
                *                {
                *                        var res:String = URLLoader(e.target).data.result
                *                        var data:* = Serializer.unserialize(res);
                *                        trace(data);
                *                }
                *        }
                *
                *  init();
                *
                *  </pre>
                */
               
                public static function unserialize(data:String):*
                {
                        Serializer.c = 0;
                        return Serializer.unserialize_internal(data);
                }
 
 
                mx_internal static function unserialize_internal(data:String):*
                {
                        var result:*;
                        var tmpvar:*;
                        var tmp:Array = new Array();
                        var type:String = data.charAt(Serializer.c);
                        var pos:uint = 0;
                        var islist:Boolean = true;
                        var i:uint;
 
                        switch(type){
                                case "N":
                                        Serializer.c += 2;
                                        break;
                                case "b":
                                        result = data.substr(Serializer.c+2, 1) == "1"
                                        Serializer.c += 4
                                        break;
                                case "i":
                                        tmp.push(data.indexOf(";", Serializer.c))
                                        pos = Serializer.c+2
                                        Serializer.c = tmp[0]+1
                                        result = int(data.substring(pos,tmp[0]))
                                        break;
                                case "d":
                                        tmp.push(data.indexOf(";", Serializer.c))
                                        pos = Serializer.c + 2
                                        Serializer.c = tmp[0]+1
                                        result = Number(data.substring(pos,tmp[0]))
                                        break;
                                case "s":
                                        tmp.push(int(data.indexOf(":", Serializer.c+2)))
                                        tmp.push(tmp[0]+2)
                                        pos = Serializer.c+2
                                        tmp.push(0)
                                        tmp.push(int(data.substring(pos, tmp[0])))
                                        if(tmp[3] == 0)
                                        {
                                                result = "";
                                                Serializer.c = pos+5
                                        } else {
                                                var lenc:uint = Serializer.stringCLenght(data, Serializer.c, tmp[3]);
                                                if(lenc != tmp[3])
                                                {
                                                        result = data.substr(tmp[0]+2, lenc);
                                                        Serializer.c = tmp[0]+4+lenc;
                                                } else {
                                                        result = data.substr(tmp[0]+2, tmp[3]);
                                                        Serializer.c = tmp[0]+4+tmp[3];
                                                }
                                        }
                                        if(Serializer.pattern.test(result))
                                        {
                                                result = new Date(result)
                                        }
                                        break;
                                case "a":
                                        pos = Serializer.c+2
                                        tmp.push(int(data.indexOf(":", pos)))
                                        tmp.push(int(data.substring(pos, tmp[0])))
                                        Serializer.c = tmp[0]+2
                                        result = []
                                        for(i = 0; i < tmp[1]; i++){
                                                tmpvar = Serializer.unserialize_internal(data)
                                                result[tmpvar] = Serializer.unserialize_internal(data)
                                                if(!(tmpvar is int) || tmpvar < 0){
                                                        islist = false
                                                }
                                        }
                                        if(islist){
                                                tmp.push([])
                                                for(var key:uint = 0; key < result.length; key++){
                                                        pos = tmp[2].length
                                                        while(key > pos){
                                                                tmp[2].push(null)
                                                                pos +=1
                                                        }
                                                        tmp[2].push(result[key])
                                                }
                                                result = tmp[2]
                                        }
                                        Serializer.c += 1
                                        break;
                                case "O":
                                        pos = data.indexOf("\"", Serializer.c)+1;
                                        Serializer.cdata.indexOf("\"", pos);
                                        tmp.push(data.substring(pos, Serializer.c))
                                        Serializer.c += 2
                                        i = Serializer.c
                                        Serializer.c = data.indexOf(":", i)
                                        i = int(data.substring(i, Serializer.c))
                                        Serializer.c +=2;
                                        result = {};
                                        var tmps:*;
                                        while(i > 0){
                                                tmps = Serializer.unserialize_internal(data)
                                                result[tmps] = Serializer.unserialize_internal(data)
                                                i -= 1
                                        }
                                        break;
                        }
                        return result;
                }
 
 
                mx_internal static function stringCLenght(data:String, from:uint = 0, len:uint = 0):int
                {
                        var i:uint;
                        var j:uint = len;
                        var startIndex:uint = from + 4 + len.toString().length;
                        for (i = 0; i < j; i++){
                                if (data.charCodeAt(i+startIndex) > 128)
                                {
                                        j = j - 1
                                }
                        }
                        return j;
                }
 
                mx_internal static function stringLength(data:String):uint
                {
                        var code:int  = 0
                        var result:int = 0
                        var slen:int  = data.length;
                        while(slen){
                                slen = slen - 1
                                try
                                {
                                        code = data.charCodeAt(slen)
                                } catch(e:Error){
                                        code = 65536
                                }
                                if(code < 128){
                                        result = result + 1
                                } else if(code < 2048){
                                        result = result + 2
                                } else if(code < 65536){
                                        result = result + 3
                                } else {
                                        result = result + 4
                                }
                        }
                        return result
                }
 
        }
}


AlexCooper 06.11.2012 19:22

Вложений: 1
почему вы не используете amfphp?

объявление соединения
Код AS3:

private var AMF:AMF3 = new AMF3("http://server/amfphp/Amfphp/index.php");

отправка запроса на сервер
Код AS3:

AMF.toamf("class_name/method", callback,params);

класс подключения к amfphp
Код AS3:

package service {
        import flash.net.Responder;       
        import flash.net.NetConnection;       
        import flash.events.NetStatusEvent;
        import flash.utils.Dictionary;
        import flash.utils.ByteArray;
 
        public class AMF3 {
 
                private var nc : NetConnection = new NetConnection();
                var socket:ByteArray;
 
                public function AMF3($server:String="http://localhost/amfphp/Amfphp/index.php") {
                        trace("connect to server "+$server);
                        nc.addEventListener(NetStatusEvent.NET_STATUS, handlerNC);
                        nc.connect($server);
                        nc.objectEncoding=3;
 
                }
                private function handlerNC(e:NetStatusEvent):void {
                        trace("connect"+e.info.code);
                }
 
                public  function toamf(wht:String, cb : Function, args:*=null) : void {
 
                        var resp:Responder = new Responder(cb, onFault);
 
                        trace("connect " +wht);
                        //if (args==null) nc.call(wht, resp);
                        nc.call( wht, resp, args);
                }       
 
                private function onFault(res:Object):void {
                        trace('к севраку не достучались.');
 
                        for( var item in res) {
                                trace(item+" >> "+res[item])
                        }
                }
        }               
}

В вложении скинул Вам рабочею версию AMFPHP.
Серверные скрипты размещать в amfphp/Amfphp/service

PHP код:

<?php

class class_name {

    public function 
__construct() {

        
$host       "localhost";
        
$database   "";
        
$user       "";
        
$pass       "";

        
$this->conn mysql_connect($host,$user,$pass,$database) or die(mysql_error());

        
mysql_query('set character utf8');
         
mysql_query('set names utf8');
    }

    public function 
method($data) {
        
$data $this->extra($data); // <<--- Ненашел ответа с чем связанно но иногда терялись индексы, написал эту функции и стабильность передачи 100%
        
return $data;
    }

    private function 
extra($data) {
        
$return = array();

        foreach ( 
$data as $key => $value ) {
           
$return[$key]=$value;
        }

        return 
$return;
    }
    
?>


КорДум 06.11.2012 19:28

Код-то какой неаккуратный.
При первом взгляде в serialize надо бы поменять блоки проверки на Array и Object местами.

rolling_kz 06.11.2012 19:29

так исторически сложилось, отправляем постом сериализированную строку, в ответ то же получаем сериализированную строку.
в итоге очень легко передавать любые структуры данных.

rolling_kz 06.11.2012 19:30

Цитата:

Сообщение от КорДум (Сообщение 1103070)
Код-то какой неаккуратный.
При первом взгляде в serialize надо бы поменять блоки проверки на Array и Object местами.

- в каких строках?

КорДум 06.11.2012 19:32

Цитата:

- в каких строках?
В строках метода serialize, где идет проверка на Object и Array. Нужно оба этих блока поменять местами.

rolling_kz 06.11.2012 19:33

Цитата:

Сообщение от AlexCooper (Сообщение 1103073)
В вложении скинул Вам рабочею версию AMFPHP.
Серверные скрипты размещать в amfphp/Amfphp/service

на стороне сервера используем Zend Amf

КорДум 06.11.2012 19:33

Код AS3:

} else if(data is Object){
        for(key in data){
                tmp.push(Serializer.serialize(key));
                tmp.push(Serializer.serialize(data[key]));
                i += 1;
        }
        s = "O:8:\"stdClass\":" + i + ":{" + tmp.join("") + "}";
} else if(data is Array){
        for(key in data){
                tmp.push(Serializer.serialize(i))
                tmp.push(Serializer.serialize(data[key]))
                i += 1
        }
        s = "a:"+i+":{"+ tmp.join("") + "}";


AlexCooper 06.11.2012 19:38

Цитата:

Сообщение от rolling_kz (Сообщение 1103078)
на стороне сервера используем Zend Amf

Дело Ваше.

rolling_kz 06.11.2012 19:38

из case "a": переставил в case "O" и наоборот - не работает

КорДум 06.11.2012 19:44

Ну вообще-то надо целиком блоки менять. И в том методе нет кейсов вообще. Там только ифы.
Не уверен, что это как-то вам поможет, конечно, но по логике это будет правильно. Иначе массив никогда не сериализуется.

rolling_kz 06.11.2012 19:49

Цитата:

Сообщение от КорДум (Сообщение 1103079)
Код AS3:

} else if(data is Object){
        for(key in data){
                tmp.push(Serializer.serialize(key));
                tmp.push(Serializer.serialize(data[key]));
                i += 1;
        }
        s = "O:8:\"stdClass\":" + i + ":{" + tmp.join("") + "}";
} else if(data is Array){
        for(key in data){
                tmp.push(Serializer.serialize(i))
                tmp.push(Serializer.serialize(data[key]))
                i += 1
        }
        s = "a:"+i+":{"+ tmp.join("") + "}";


так не помогло,
сериализируется и так отлично. такой массив php без ошибки десериализует.
а вот во флаше-то я его обратно десериализвать не могу.

КорДум 06.11.2012 19:51

У вас не будет сериализовать отлично, если там будет массив. Понятно? Только и всего. Конкретно по проблеме пытаюсь помочь. Пишу десериализатор на скорую руку.

rolling_kz 06.11.2012 19:56

понятно, черт с ним с массивом. не используем.

Добавлено через 3 минуты
хотя вот:
Код AS3:

                                var obj:Object = new Object;
                                obj.aaa = new Array();
                                obj.aaa[0]=0;
                                obj.aaa[1]=1;
                                obj.aaa[2]=2;
                                var tmpStr:String = Serializer.serialize(obj);
 
                                var obj2:* = Serializer.unserialize(tmpStr);

при отладке дает obj2:
Код AS3:

obj2        Object (@5bcf401)        
        aaa        Object (@5bcf479)       
                [0]        0       
                [1]        1       
                [2]        2


КорДум 06.11.2012 20:01

А должен быть массив.

rolling_kz 06.11.2012 20:03

но как только два массива:
Код AS3:

var obj:Object = new Object;
                                obj.aaa = new Array();
                                obj.aaa[0]=0;
                                obj.aaa[1]=1;
                                obj.aaa[2]=2;
                                obj.bbb = new Array();
                                obj.bbb[0]=0;
                                obj.bbb[1]=1;
                                obj.bbb[2]=2;
                                var tmpStr:String = Serializer.serialize(obj);
 
                                var obj2:* = Serializer.unserialize(tmpStr);

то начинается глюк:
Код AS3:

obj2        Object (@5d4c731)        
        bbb        Object (@5d4c7a9)       
        undefined        undefined

Код AS3:

tmpStr        "O:8:"stdClass":2:{s:3:"bbb";O:8:"stdClass":3:{s:1:"0";i:0;s:1:"1";i:1;s:1:"2";i:2;}s:3:"aaa";O:8:"stdClass":3:{s:1:"0";i:0;s:1:"1";i:1;s:1:"2";i:2;}}"

Добавлено через 1 минуту
я понял про что Вы говорите. да пусть станет объектом, хотя согласен коряво написано.

Добавлено через 2 минуты
главная проблема только один объект или массив пропускает.

GBee 06.11.2012 20:16

А почему обычный ДЖСон не устроил? Я не вижу типизированных объектов.

КорДум 06.11.2012 20:23

Да на самом деле. Я вот щас десериализатор пишу и меня уже задолбало. То ли бошк из-за недосыпа не варит. В любом случае, это такой геморрой. А JSON явно тут был бы к месту. Тем более, есть нативная поддержка, что на пхп, что на ас3.

GBee 06.11.2012 20:27

PHP код:

<?php
    
class foo
    
{
        var 
$aaa = array(0,1,2);
        var 
$bbb = array(0,1,2);
    }
    
$obj = new foo;
    echo 
serialize($obj);
?>

дает

O:3:"foo":2:{s:3:"aaa";a:3:{i:0;i:0;i:1;i:1;i:2;i:2;}s:3:"bbb";a:3:{i:0;i:0;i:1;i:1;i:2;i:2;}}

Цитата:

tmpStr "O:8:"stdClass":2:{s:3:"bbb";O:8:"stdClass":3:{s:1:"0";i:0;s:1:"1";i:1;s:1:"2";i:2;}s:3:"aaa";O:8:"stdClass":3:{s:1:"0";i:0;s:1:"1";i:1;s:1:"2";i:2;}} "

rolling_kz 06.11.2012 20:28

Цитата:

Сообщение от КорДум (Сообщение 1103112)
Да на самом деле. Я вот щас десериализатор пишу и меня уже задолбало. То ли бошк из-за недосыпа не варит. В любом случае, это такой геморрой. А JSON явно тут был бы к месту. Тем более, есть нативная поддержка, что на пхп, что на ас3.

ну вроде php.serialize - нативно тоже.

а в остальном не вижу преимуществ JSON.

GBee 06.11.2012 20:28

о ходу весь класс кривой. и сериализатор и обратно

Добавлено через 1 минуту
Цитата:

а в остальном не вижу преимуществ JSON.
Он работает! :о)

rolling_kz 06.11.2012 20:36

так и этот работает.
много лет юзаем. только вот обна бага попалась.
до этого с php только плоские объекты посылали типа:
Код AS3:

var obj:Object = {aaa:1, bbb:2 };

Добавлено через 46 секунд
а вот из флаша туда многосложные объекты отправляем все без багов.

dimarik 06.11.2012 22:46

Цитата:

Сообщение от КорДум (Сообщение 1103079)
При первом взгляде в serialize надо бы поменять блоки проверки на Array и Object местами.
Код AS3:

 
} else if(data is Object){
//<skipped>
} else if(data is Array){
//<skipped>
}


Однозначно поменять

Код AS3:

trace([] is Object);// true

Добавлено через 6 минут
Цитата:

Сообщение от rolling_kz (Сообщение 1103121)
так и этот работает.
много лет юзаем. только вот обна бага попалась.

Тут пустяковый баг, но сразу рекомендуют на альтернативные форматы переходить.

SE|PY помните? Тот, что для AS2. Это его рук дело. Я только его и пользовал во времена TimeZero.

rolling_kz 06.11.2012 23:24

да кстати он ответил, не могу говорит помоч, давно это было, as3 давно не использует.

SE|PY - классный редактор был.

ну пустяковый баг пока не решается. замена array на object не помогает.

terbooter 07.11.2012 17:11

Зачем вам использовать кукую-то библиотеку, которая не работает и не поддерживается.
Мы раньше тоже использовали разные странности вроде ZendAMF. И даже все работало. Но вдруг на каком-то "особенном" объекте вылетала бага.
Как уже советовали, используйте JSON.
Если хотите получить защиту от кулхакеров с Charles, то лучше написать свое шифратор-дешифратор


Часовой пояс GMT +4, время: 07:50.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.