Function unserialize offset error - php

I'm building a multilanguage website with Laravel4.
In the database i have column named "content" that contains serialized values for multiple languages. For example:
a:3:{s:2:"gb";s:15:"This is English";s:2:"es";s:5:"Hola!";s:2:"si";s:19:"Slovenija je zakon!";}
The serialized array contains of:
Language abbreviation, taken from Session
Content that comes from the input field
Now when I add new language to the database it creates new serialized string. Great!
But when I want to unserialize that string and add a value into it, i get the following error:
unserialize() [<a href='function.unserialize'>function.unserialize</a>]: Error at offset 0 of 30 bytes
Any ideas what is going on? I understand the meaning of the error, but it just makes no sense, since I'm sure that value in the database is serialized string.
public function setContentAttribute($value)
{
$lang = (Session::has('my.locale') ? Session::get('my.locale') : Config::get('app.locale'));
/* Create new serialized string */
if(empty($this->content)) {
$data[$lang] = $value['content'];
$this->attributes['content'] = serialize($data);
/* Update values */
} else {
$data = $this->content;
$data = unserialize($data)
$data[$lang] = $value['content'];
$this->attributes['content'] = serialize($data);
}
}
P.S: I'm using mutators for adding values to database.
I hope it's clear enough. If there is anything unclear, please comment and I'll fix it.
Thanks!

Ok, I've managed to fix it. I was unserializing my code twice - once in the accessor and once in the mutator. Here is a working example:
public function getVsebinaAttribute($value)
{
$data = unserialize($value);
$lang = $this->getLang();
if (!empty($data[$lang])) {
return $data[$lang];
} else {
return '# Value has not yet been added';
}
}
public function setVsebinaAttribute($value)
{
if (isset($this->attributes['vsebina'])) {
$data = unserialize($this->attributes['vsebina']);
} else {
$data = array();
}
$lang = $this->getLang();
$data[$lang] = $value;
$this->attributes['vsebina'] = serialize($data);
}
protected function getLang()
{
return Session::has('my.locale') ? Session::get('my.locale') : Config::get('app.locale');
}

Related

How to append unique ID to a json array - OctoberCMS / Laravel

OctoberCMS BackendForm-Widget "Repeater" stores my data as an array in the database which looks like so:
{
"topic":"title",
"topic_description":"description",
}
{
"topic":"title",
"topic_description":"description",
}
I need to add a unique ID to each array so the json looks like this:
{
"topic_id":"1",
"topic":"title",
"topic_description":"description",
}
{
"topic_id":"2",
"topic":"title",
"topic_description":"description",
}
I have added this formBeforeSave function to my controller:
public function formBeforeSave($model)
{
$model->topics = array_map(array($model, 'topics'), function ($topic) {
$topic['id'] = uniqid();
});
}
But when trying to save the form OctoberCMS throws this error:
“array_map(): Argument #2 should be an array”
Adding this to the controller instead:
public function formBeforeSave($model)
{
$model->topics = array_map($model->topics, function ($topic) {
$topic['id'] = uniqid();
});
}
Throws the error:
array_map() expects parameter 1 to be a valid callback, array must have exactly two members
Has anyone experienced this and found a solution he/she could share please?
Each topic has a (unique) key already. So you could just copy this key as additional value while walking through the array:
// mocking test-data:
// $model->topics = [["topic"=>"title"], ["bar"=>"foo"]];
array_walk($model->topics, function(&$topic, $key) {
$topic['topic_id'] = $key;
});
As per the docs first argument should be callback, replace your code with following and try if it works.
public function formBeforeSave($model)
{
$model->topics = array_map(function ($topic) {
$topic['id'] = uniqid();
return $topic;
}, $model->topics);
}
Reference: http://php.net/manual/en/function.array-map.php
Applaus goes to LukeTower who pointed me to the right direction on Github.
The solution is putting the logic in the beforeSave() method on the model:
public function beforeSave()
{
$this->_FieldName_ = array_map(function ($miau) {
$miau['id'] = uniqid();
return $miau;
}, $this->_FieldName_);
}

Query string and use that value to influence the targetted column in MySQL

I have a webpage that I want to be show in different language when changing the query string, ie; mypage.php?langue=en_en
I'm able to do it with the code I found from bumperbox:
https://codereview.stackexchange.com/questions/39787/multi-language-website-management
I change the code to be able to make the language selection with a query string:
Original code
class lang {
private $lang = null;
function __construct($lang) {
$this->lang = parse_ini_file("{$lang}.ini");
}
public function xlate($str) {
$arg_count = func_num_args();
if ($arg_count > 1) {
$params = func_get_args();
// strip first arg
array_shift($params);
} else {
$params = array();
}
$out_str = isset($this->lang[$str]) ? $this->lang[$str] : null;
// if you string doesn't exist or is mistyped, then blow up, so we know about it
// or you could even go away to google translate and perform the translation for
// any missing strings
if (!$out_str) {
throw new exception("Lang String Not Found: $str");
}
return vsprintf($out_str, $params);
}
}
$lang = new lang('fr_fr');
I have changed the last line:
$lang = new lang('fr_fr');
for :
$lang = new lang(mysql_real_escape_string($_GET['langue']));
So I can select the language (fr_fr or en_en) from the url with mypage.php/langue=fr_fr
This works well.
My issue is that I would like to show a different column in my sqlquery depending of that query string.
while($row = mysql_fetch_array($rs)) {
if($lang == "fr_fr"){
$tmpTarget="code_produit";
}
else {
$tmpTarget="product_code";
}
echo "<tr><td>$row[$tmpTarget]</td></tr>"
This doesn't work, it always bring me back the else result even if my language selection is french.
I tried several things but nothing worked so far. I really don't know what else to do. I simply need that if $lang = the selection made in the query string, then my tmpTarget would be a different value so I can show the french name of the product code which is in a different column in my table.
Thank you in advance for your help!!! Much appreciated!
$lang = new lang('fr_fr');
sets $lang to an object, not a string. You need to add code to your lang class that returns the name of the language.
class lang {
private $lang = null;
public $name;
function __construct($lang) {
$this->lang = parse_ini_file("{$lang}.ini");
$this->name = $lang;
}
public function xlate($str) {
$arg_count = func_num_args();
if ($arg_count > 1) {
$params = func_get_args();
// strip first arg
array_shift($params);
} else {
$params = array();
}
$out_str = isset($this->lang[$str]) ? $this->lang[$str] : null;
// if you string doesn't exist or is mistyped, then blow up, so we know about it
// or you could even go away to google translate and perform the translation for
// any missing strings
if (!$out_str) {
throw new exception("Lang String Not Found: $str");
}
return vsprintf($out_str, $params);
}
}
Then you can do:
if ($lang->name == "fr_fr") {
$tmpTarget = "code_produit";
} else {
$tmpTarget = "product_code";
}
BTW, I would put that if statement before the while loop, since the condition doesn't change for each row.

Loop to get user data

I can't put real code here because is very long and will be hard to
explain.
I have users table in database and I have data table in database too.
So, to get the user data I'll pass user_id as parameter. Like this:
public function get_user_data($user_id) {
}
But. I can only get 1 data per "request". (Keep reading)
public function user_data() {
$getUsers = $this->db->get('users');
foreach($getUsers->result_array() as $user)
{
$data = $this->get_user_data($user->ID);
var_dump($data); // Only return 1 data;
}
}
But, I guess that have an way to "bypass" this but I don't know. I'm having trouble thinking.
As I said, I want to "bypass" this, and be able to send multiple user IDs, my real function do not accept that by default and can't be changed.
Thanks in advance!
replace
foreach($getUsers->result_array() as $user)
{
$data = $this->get_user_data($user->ID);
var_dump($data); // Only return 1 data;
}
to this
foreach($getUsers->result_array() as $user)
{
$data[] = $this->get_user_data($user->ID);
}
var_dump($data);
If you are aiming at sending more data to the function, you always need to make signature change of your function as one of the below :
function get_user_data() {
$args = func_get_args();
/** now you can access these as $args[0], $args[1] **/
}
Or
function get_user_data(...$user_ids) {
/** now you can access these as $user_ids[0], $user_ids[1] **/
}
// Only higher version of PHP
But I am not sure how you will handle returning data.
EDIT: Yes, then in the function, you can collect data in array and return an array of data from function.
If you can change in your function from where to where_in I think you will get an easy solution.
public function get_user_data($user_ids)
{
// your db code
$this->db->where_in('ID',$user_ids); //replace where with where_in
}
public function user_data()
{
$getUsers = $this->db->get('users');
foreach($getUsers->result_array() as $user)
{
$user_ids[] = $user->ID;
}
$this->get_user_data($user_ids);
}

How to search for multiple values in a single field of mysql table using codeigniter active record?

I have to search for multiple values in a field using mysql in codeigniter. Here follows my code.
In Controller
public function vpsearch()
{
$data['info'] = $this->psearch_m->emp_search_form();
$this->load->view("employer/result",$data);
}
IN Model
public function emp_search_form()
{
$skill = $this->security->xss_clean($this->input->post('ps_skills'));
$jrole = $this->input->post('ps_jobrole'));
if ( $jrole !== NULL)
{
return $this->db->get('js_edu_details');
$this->db->like('js_skills','$skill');
}
}
In view i.e, (../employer/result)
foreach($info->result() as $row)
{
echo $row->js_id."<br/><br/>" ;
}
However I am getting all the records in 'js_edu_details' table instead of fields having searched 'skills'.
Where I am going wrong? Any help wud b appreciated, thanx in advance.
Try:
public function emp_search_form()
{
$skill = $this->security->xss_clean($this->input->post('ps_skills'));
//$skill = $this->input->post('ps_skills', true); other short way of getting the above result with `xss clean`
if ( $jrole !== NULL)
{
$this->db->like('js_skills',$skill); #remove the single quote around the `$skill`
$res = $this->db->get('js_edu_details');
echo $this->db->last_query(); #try to print the query generated
return $res;
}
}
Return statement should be after the like statement
You should arrange the code properly like this
public function emp_search_form()
{
$ps_skills = $this->input->post('ps_skills')
$skill = $this->security->xss_clean($ps_skills);
if ( $jrole !== NULL)
{
$this->db->like('js_skills','$skill');
return $this->db->get('js_edu_details');
}
}
Also you should note the condition will never meet. It will always give error undefined variable $jrole

php passing object of an object: reference or value?

Hi all I'm using zend framework (but I think this is irrelevant) and php5 and I just want to modify an object of an object
public function saveSite($post) {
$form = new Diff_Form_Download();
$subform = new Diff_Form_DownloadSubform();
$form = $this->view->form;
$newSite = 0;
$sitesRecord = new Diff_Model_Sites();
$debugString = null;
if (is_array($post)) {
$subform = $this->getSubformByPost($post);
$debugString = $subform->getContent();
echo $debugString;
//new site instertion
if (is_null($subform)) {
$subform = $form->getSubForm('NewSite');
$newSite = 1;
}
$values = reset($subform->getValues());
$sitesRecord = Doctrine_Core::getTable('Diff_Model_Sites')->findOneBy('idSite', $values['idSite']);
if ($sitesRecord) {
$sitesRecord->idSite = $values['idSite']; //useless but necessary to make Doctrine understand to use update?
} else { //if the record is not present instantiate a new object (otherwise save() will not work
$sitesRecord = new Diff_Model_Sites();
}
$sitesRecord->content = $subform->getContent(); //$values['content'];
$sitesRecord->newHtml = $subform->getContent();
$sitesRecord->url = $values['url'];
$sitesRecord->shortName = $values['shortName'];
$sitesRecord->lastChanged = date("Y-m-d H:i:s");
$sitesRecord->pollingHours = $values['pollingHours'];
$sitesRecord->minLengthChange = $values['minLenghtChange'];
if (Zend_Auth::getInstance()->hasIdentity()) { //save the owner
$sitesRecord->idOwner = Zend_Auth::getInstance()->getIdentity()->idOwner; //retrieve the owner
$sitesRecord->save();
} else {
throw new Exception("your session have expired: \n please login again");
}
}
}
/**
* return the calling subform
* #param type $post
* #return type
*/
public function getSubformByPost($post) {
$form = new Diff_Form_Download();
$form = $this->view->form;
$subform = new Diff_Form_DownloadSubform();
$subformName = "site" . $post['idSite'];
$subform = $form->getSubForm($subformName);
return $subform;
}
public function refreshOneDiff($post) {
$debugString;
if (is_array($post)) {
$form = new Diff_Form_Download();
$form = $this->view->form;
$subform = new Diff_Form_DownloadSubform();
$subform = $this->getSubformByPost($post);
if (!$subform)
$subform = $this->view->form->getSubformByPost('NewSite');
$url = $subform->getUrl();
$idSite = $subform->getIdSite();
$crawler = new Crawler();
$newpageContent = $crawler->get_web_page($url);
$siteRecord = new Diff_Model_Sites();
$siteRecord = $subform->getSiteRecord();
if ($siteRecord) //check if the record is not null
$oldpageContent = $siteRecord->get('content');
else
$oldpageContent = null;
$differences = $this->getDiff($oldpageContent, $newpageContent);
if (!is_null($differences)) {
$siteRecord->content = $newpageContent;
$subform->setContent($newpageContent);
$subform->setContentDiff($differences);
$subform->setSiteRecord($siteRecord);
$subform = $this->getSubformByPost($post);
$debugString = $subform->getContent();
}
//echo $debugString;
$sitePresence = Doctrine_Core::getTable('Diff_Model_Sites')->findOneBy('idSite', $idSite);
if ($sitePresence) {
//$this->saveSite($post);
$this->debugtry($post);
}
} else {
}
}
Basically what I'm doing here is:
1) grab a the form from the view
2) grab a subform from the form (let's call it SubformX)
3) grab an object "siteRecordX" from SubformX
4) change a value of "siteRecordX"
5) call a function saveRecord()
6) In this function regrab the same SubformX and echoing the value of the object siteRecordX
Surprisingly if i change a variable of SubformX it will stay that way, if I change a variable of an object of SubformX it will remain unchanged (if I retrieve SubformX).
It looks like, even if SubformX is passed by reference it is not the same for it's subobjects, wich are passed by value and so they disappear changing the context of the function.
Can you please help me?
Thanks
EDIT
I still cannot solve this issue nor understand it:
This is the constructor of the subform:
public function __construct($site = null, $options = null) {
if ($site instanceof Diff_Model_Sites) {
$this->_shortName = $site->get('shortName');
$this->_url = $site->get('url');
$this->_content = $site->get('content');
$this->_idSite = $site->get('idSite');
$this->_siteRecord = $site;
$this->_lastChanged = $site->get('lastChanged');
}parent::__construct($options);}
while this is the function of SubformX i use to set the value.
public function setContent($contentText) {
$this->_siteRecord->content = $contentText;
$this->_content = $contentText;
}
and this is the function of the subform that I call to get the value
public function getContent() {
if (isset($this->_siteRecord)) {
//return $this->_content;
return $this->_siteRecord->content;
}
}
with the commented line I'm able to retrieve the updated value, not with the second.
This is a real mystery to me because i set and get them exactly the same way at exactly the same point and i cannot understand the difference.
Your _siteRecord property is an ORM object (Doctrine, it appears). So its data may have some behaviors that are not standard for a reference-type object. It surely has some override of __get and __set. It also employs caching. These things are necessary to keep the database-model interaction working properly, but they can confuse what should be a reference and value types. (See: http://www.codinghorror.com/blog/2006/06/object-relational-mapping-is-the-vietnam-of-computer-science.html)
P.S.: in your constructor you use:
$this->_content = $site->get('content');
$this->_siteRecord = $site;
but in your getContent() you use:
$this->_siteRecord->content;
That difference might be part of the problem.
Thank you all guys. It was Doctrine caching.
I have not investigated further the problem, but after getting rid of Doctrine everything works fine.
I have lost one entire day after this issue.
Moreover today I have lost another day for another curious problem related to Doctrine.
It seems that each time you gather data from your db Doctrine decode them for you (just like the php function utf8_decode($data).
Of course if you get the data and then put it back in the db again it will result in a total mayhem of coding and decoding.
This is enough. I still think that ORM are great programming tools but simply Doctrine is not.
I will not rest in peace since I'll have it eliminated from my program.
I will use Zend_Db library instead. Which I have mostly already done without regret and without facing the above-mentioned Doctrine's problems.
Again thanks to Seth Battin and Dave Random for the help and patience to understand my noob-coding.

Categories