I've been trying to find a solution to this problem for a long time now and nowhere on the internet was I able to find the answer. I have this situation where i need to insert or update a blob field (subtype 1) from a firebird database with php. The problem is that when the text get like really big >36k it will not execute the query. I know line queries are limited to 32k of data and I tried to use parametrized queries in c#, but i was not able to find something to work for me in PHP. Not even close to working.
I tried with ibase_blob_Create and so on i tried inserting directly like Insert into table (blob_value) values (?), ibase_prepare that and so on. Nothing seems to work for me. Is there some magical way to make this work in php or is it just impossible to get large text into blob from php?
Ive tried using things like:
class DBMgmt_Ibase_Blob extends DBMgmt_Generic_Blob
{
var $blob; // resourse link
var $id;
var $database;
function DBMgmt_Ibase_Blob(&$database, $id=null)
{
$this->database =& $database;
$this->id = $id;
$this->blob = null;
}
function read($len)
{
if ($this->id === false) return ''; // wr-only blob
if (!($e=$this->_firstUse())) {
return $e;
}
$data = #ibase_blob_get($this->blob, $len);
if ($data === false) return $this->_setDbError('read');
return $data;
}
function write($data)
{
if (!($e=$this->_firstUse())) return $e;
$ok = #ibase_blob_add($this->blob, $data);
if ($ok === false) return $this->_setDbError('add data to');
return true;
}
function close()
{
if (!($e=$this->_firstUse())) return $e;
if ($this->blob) {
$id = #ibase_blob_close($this->blob);
if ($id === false) return $this->_setDbError('close');
$this->blob = null;
} else {
$id = null;
}
return $this->id ? $this->id : $id;
}
function length()
{
if ($this->id === false) return 0; // wr-only blob
if (!($e=$this->_firstUse())) return $e;
$info = #ibase_blob_info($this->id);
if (!$info) return $this->_setDbError('get length of');
return $info[0];
}
function _setDbError($query)
{
$hId = $this->id === null ? "null" : ($this->id === false ? "false" : $this->id);
$query = "-- $query BLOB $hId";
$this->database->_setDbError($query);
}
// Called on each blob use (reading or writing).
function _firstUse()
{
// BLOB is opened - nothing to do.
if (is_resource($this->blob)) return true;
// Open or create blob.
if ($this->id !== null) {
$this->blob = #ibase_blob_open($this->id);
if ($this->blob === false) return $this->_setDbError('open');
} else {
$this->blob = #ibase_blob_create($this->database->link);
if ($this->blob === false) return $this->_setDbError('create');
}
return true;
}
}
Which i use like this:
$text = new DBMgmt_Ibase_Blob($DB);
if (!$text->write(htmlspecialchars($Data["Text"]))){
throw new Exception("blob fail");
}
$blobid = $text->close();
//similar query
$DB->query("INSERT INTO TABLE1 (BLOB_VALUE) VALUES (?)",$blobid);
After that in my database I find a number which I know I have to use with:
Blob = new DBMgmt_Ibase_Blob($DB,$data->Text);
$data->Text = $Blob->read($Blob->length());
But i get String is not a BLOB ID with a number in database like 30064771072.
I tried directly to add it but of course it does not work like this
$DB->query('insert into table (blob) values (?)',$string); // where string is like 170k chars
I get error of Dynamic SQL Error SQL error code = -104 Unexpected end of command - line 1, column 236
I tryed putting it into file following php.net reference php.net blob_import with code similar to this:
$dbh = ibase_connect($host, $username, $password);
$filename = '/tmp/bar';
$fd = fopen($filename, 'r');
if ($fd) {
$blob = ibase_blob_import($dbh, $fd);
fclose($fd);
if (!is_string($blob)) {
// import failed
} else {
$query = "INSERT INTO foo (name, data) VALUES ('$filename', ?)";
$prepared = ibase_prepare($dbh, $query);
if (!ibase_execute($prepared, $blob)) {
// record insertion failed
}
}
} else {
// unable to open
But I am still getting result like the blob writing method.
You need to use parameters :
$query = ibase_prepare($DB, 'insert into table (blob) values (?)');
ibase_execute($query, $string);
cf : http://php.net/manual/en/function.ibase-execute.php
Related
I have a controller working like this'
public function indexAction() {
// some stuff cut out
$openEntries = $this->checkOpenEntries($position);
if($openEntries === 0) {
//do some stuff
}
elseif ($openEntries === -1) {
//Sends email to notify about the problem
$body = 'Tried to create position log entry but found more than 1 open log entry for position ' . $position->getName() . ' in ' . $position->getACRGroup()->getName() . ' this should not be possible, there appears to be corrupt data in the database.';
$this->email($body);
return new response($body . ' An automatic email has been sent to it#domain.se to notify of the problem, manual inspection is required.');
} else {
//do some other stuff
}
}
private function checkOpenEntries($position) {
//Get all open entries for position
$repository = $this->getDoctrine()->getRepository('PoslogBundle:Entry');
$query = $repository->createQueryBuilder('e')
->where('e.stop is NULL and e.position = :position')
->setParameter('position', $position)
->getQuery();
$results = $query->getResult();
if(!isset($results[0])) {
return 0; //tells caller that there are no open entries
} else {
if (count($results) === 1) {
return $results[0]; //if exactly one open entry, return that object to caller
} else {
return -1; //if more than one open entry, null will signify to caller that we have a problem.
}
}
}
But I would like to put that response-returning-business already in the private function to clean up my indexAction, but that is not possible, the indexAction will keep going past the point of
$openEntries = $this->checkOpenEntries($position);
even if checkOpenEntries attempts to return a HTTP response.
Ideally I would like it to look like this, is there a way to accomplish that:
public function indexAction() {
// some stuff cut out
$openEntries = $this->checkOpenEntries($position);
if($openEntries === 0) {
//do some stuff
} else {
//do some other stuff
}
}
private function checkOpenEntries($position) {
//Get all open entries for position
$repository = $this->getDoctrine()->getRepository('PoslogBundle:Entry');
$query = $repository->createQueryBuilder('e')
->where('e.stop is NULL and e.position = :position')
->setParameter('position', $position)
->getQuery();
$results = $query->getResult();
if(!isset($results[0])) {
return 0; //tells caller that there are no open entries
} else {
if (count($results) === 1) {
return $results[0]; //if exactly one open entry, return that object to caller
} else {
//Sends email to notify about the problem
$body = 'Tried to create position log entry but found more than 1 open log entry for position ' . $position->getName() . ' in ' . $position->getACRGroup()->getName() . ' this should not be possible, there appears to be corrupt data in the database.';
$this->email($body);
return new response($body . ' An automatic email has been sent to it#domain.se to notify of the problem, manual inspection is required.');
}
}
}
IMHO, it is not clean the way you mix up the type of method. However, you could do something like this, to make it work.
In addition, I think it would be better if functions and parameters have type, it would be easier to read.
public function indexAction() {
// some stuff cut out
$openEntries = $this->checkOpenEntries($position);
if ($openEntries instanceOf Response) return $openEntries;
if($openEntries === 0) {
//do some stuff
} else {
//do some other stuff
}
// you might also want to add some response here!
return new Response('...');
}
I'm trying to build a permission/action control system for my users.
There are 3 tables:
appName_actions:
appName_roles:
appName_roles_members:
There are 2 functions that will obtain the relevant data:
$memRoleIDs = AccessControl::get_memberRoleIDs($appName);
$memActionIDs = AccessControl::get_memberActionIDs($appName, $memRoleIDs);
get_memberRoleIDs works fine, it targets member 327 and returns the desired '2,4'
That is then passed to get_memberActionIDs as '2,4'
It's at this point I'm having trouble working out how to return all the actionIDs in one variable/string.
get_memberActionIDs:
public static function get_memberActionIDs($appName = NULL, $memRoleIDs = NULL)
{
if($appName !== NULL && $memRoleIDs !== NULL)
{
$tbl = 'app_'.$appName.'_roles';
$memRoleID = explode(',',$memRoleIDs);
foreach($memRoleID as $value)
{
$db = openDB();
$sql = $db->prepare("SELECT actionIDs FROM $tbl WHERE roleID = '$value'");
if(!$sql->execute())
{
logThis('ERROR_crit' , 'Database Query Failed !!!' , 1 , __FILE__ , __LINE__);
die('<h2>There was a critical error and data has not been loaded correctly. Developers have been notified.</h2><h3>Please try reloading the page</h3>');
}
else
{
// sql executed ok - bind fetch results
$sql->bind_result($actionID);
$sql->fetch();
print $actionID.'<br>';
}
}// return all the actionIDs as 1 variable here
}
}// end func
Now with this, there is success up-to-a-point. It prints out the correct info:
1,2,3,4
5
And this is where I cannot go any further :(
I've looked into GROUP_CONCAT and CONCAT in the SELECT statement and .= in the PHP loop, but I just cannot figure this out.
I'd like to return this as '1,2,3,4,5' all in 1 string.
If you could point me in the right direction I would be very grateful :)
Instead of printing out separate results, create a single string and print after the loop exits. You say you've tried this but you didn't include the relevant code to check if the implementation is correct. Is this what you did?
public static function get_memberActionIDs($appName = NULL, $memRoleIDs = NULL)
{
if($appName !== NULL && $memRoleIDs !== NULL)
{
$tbl = 'app_'.$appName.'_roles';
$memRoleID = explode(',',$memRoleIDs);
$result = "";
foreach($memRoleID as $value)
{
$db = openDB();
$sql = $db->prepare("SELECT actionIDs FROM $tbl WHERE roleID = '$value'");
if(!$sql->execute())
{
logThis('ERROR_crit' , 'Database Query Failed !!!' , 1 , __FILE__ , __LINE__);
die('<h2>There was a critical error and data has not been loaded correctly. Developers have been notified.</h2><h3>Please try reloading the page</h3>');
}
else
{
// sql executed ok - bind fetch results
$sql->bind_result($actionID);
$sql->fetch();
$result .= $actionID;
}
}// return all the actionIDs as 1 variable here
print $result.'<br>';
}
}// end func
I am trying to check whether a generated string is in my database table or not.
If there is no duplicate I want to return and save it.
If there is a duplicate I want to generate a new string and save it
currently this function does not return me the generated token:
public function checkForHashDuplicate($string)
{
$newToken = '';
$inquiries = DB::table('inquiries')->get();
foreach($inquiries as $inquiryKey => $inquiryValue)
{
while($inquiryValue->android_device_token == $string)
{
$newToken = generateAlphanumericString();
if($newToken != $inquiryValue->android_device_token)
{
return $newToken;
}
}
}
}
$inquiry->android_device_token = $this->checkForHashDuplicate($hash);
A simplified version of your code is:
public function checkForHashDuplicate($string)
{
do {
// generate token
$newToken = generateAlphanumericString();
// find token in a DB
$duplicate = DB::table('inquiries')
->where('android_device_token', '=', $newToken)->first();
// if token is FOUND `$duplicate` has truthy value
// and `do-while` keeps running
// else `$duplicate` is falsy and `do-while` breaks
} while ($duplicate);
return $newToken;
}
Instead of using:
$inquiries = DB::table('inquiries')->get();
and loop, use where like:
$inquiries = DB::table('inquiries')->where('android_device_token', '=', $string)->get();
if( count($inquiries ) == 1 )
{
// found
}
else
{
// Not found, generate new one
}
You can check like this:
public function checkDuplicate($string){
$count = DB::table('inquiries')->where('android_device_token',$string)->count();
if($count==0){
// $string exists
return generateAlphanumericString();
}else{
// $string doesn't exists
return $string;
}
}
Now, use this function to assign value of $string or new token as
$inquiry->android_device_token = $this->checkForHashDuplicate($hash);
Hope you understand.
i watching tutorial about developing guestbook with php
this is the code that get the message with the id
public function GetMessage($id)
{
//Database
$id = (int)$id;
$gb_host = 'localhost' ;
$gb_dbname = 'guestbook' ;
$gb_username = 'root';
$gb_password = '' ;
$connection = mysqli_connect($gb_host , $gb_username , $gb_password,$gb_dbname);
$querycheck = mysqli_query($connection,"SELECT * FROM `messages` WHERE `id` = $id");
if($querycheck)
{
$message = mysqli_fetch_assoc($querycheck);
return $message;
}
else
{
mysqli_close($connection);
return NULL;
}
mysqli_close($connection);
}
why in else statment we return NULL instead of False
what's the difference between Null and False ?
The type.
False is boolean and null is a value.
So :
$test = false;
if($test === false) {
//correct
}
$test = null;
if ($test === false) {
//incorrect
} else if ($test === null) {
//correct
}
$test = false;
if(!$test) {
//correct
}
$test = null;
if(!$test) {
//correct
}
More precision in the documentation
Imho in this case and null and false are incorrect, because method should return one type of data!
In our method it should be array not special type (null) or boolean,
and it will be easy to use this method elsewhere, because everytime we know that we works with array, and we don't have write something like this:
$messages = $dao->GetMessage(27);
if (is_array($messages)) {
// ...
}
if (is_null($messages)) {
$messages = []; // because wihout it foreach will down
}
foreach ($messages as $message) {
// ...
}
And as for me it's pretty straightforward:
if we have data at db we'll receive not empty array,
if we don't have data at db - we'll receive empty array.
It's obviously!
I am working with SilverStripe, and I am working on making a newspage.
I use the DataObjectAsPage Module( http://www.ssbits.com/tutorials/2012/dataobject-as-pages-the-module/ ), I got it working when I use the admin to publish newsitems.
Now I want to use the DataObjectManager Module instead of the admin module to manage my news items. But this is where the problem exists. Everything works fine in draft mode, I can make a new newsitem and it shows up in draft. But when I want to publish a newsitem, it won't show up in the live or published mode.
I'm using the following tables:
-Dataobjectaspage table,
-Dataobjectaspage_live table,
-NewsArticle table,
-NewsArticle_Live table
The Articles have been inserted while publishing in the Dataobjectaspage table and in the NewsArticle table... But not in the _Live tables...
Seems the doPublish() function hasn't been used while 'Publishing'.
So I'm trying the use the following:
function onAfterWrite() {
parent::onAfterWrite();
DataObjectAsPage::doPublish();
}
But when I use this, it gets an error:
here is this picture
It seems to be in a loop....
I've got the NewsArticle.php file where I use this function:
function onAfterWrite() {
parent::onAfterWrite();
DataObjectAsPage::doPublish();
}
This function calls the DataObjectAsPage.php file and uses this code:
function doPublish() {
if (!$this->canPublish()) return false;
$original = Versioned::get_one_by_stage("DataObjectAsPage", "Live", "\"DataObjectAsPage\".\"ID\" = $this->ID");
if(!$original) $original = new DataObjectAsPage();
// Handle activities undertaken by decorators
$this->invokeWithExtensions('onBeforePublish', $original);
$this->Status = "Published";
//$this->PublishedByID = Member::currentUser()->ID;
$this->write();
$this->publish("Stage", "Live");
// Handle activities undertaken by decorators
$this->invokeWithExtensions('onAfterPublish', $original);
return true;
}
And then it goes to DataObject.php file and uses the write function ():
public function write($showDebug = false, $forceInsert = false, $forceWrite = false, $writeComponents = false) {
$firstWrite = false;
$this->brokenOnWrite = true;
$isNewRecord = false;
if(self::get_validation_enabled()) {
$valid = $this->validate();
if(!$valid->valid()) {
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
throw new ValidationException($valid, "Validation error writing a $this->class object: " . $valid->message() . ". Object not written.", E_USER_WARNING);
return false;
}
}
$this->onBeforeWrite();
if($this->brokenOnWrite) {
user_error("$this->class has a broken onBeforeWrite() function. Make sure that you call parent::onBeforeWrite().", E_USER_ERROR);
}
// New record = everything has changed
if(($this->ID && is_numeric($this->ID)) && !$forceInsert) {
$dbCommand = 'update';
// Update the changed array with references to changed obj-fields
foreach($this->record as $k => $v) {
if(is_object($v) && method_exists($v, 'isChanged') && $v->isChanged()) {
$this->changed[$k] = true;
}
}
} else{
$dbCommand = 'insert';
$this->changed = array();
foreach($this->record as $k => $v) {
$this->changed[$k] = 2;
}
$firstWrite = true;
}
// No changes made
if($this->changed) {
foreach($this->getClassAncestry() as $ancestor) {
if(self::has_own_table($ancestor))
$ancestry[] = $ancestor;
}
// Look for some changes to make
if(!$forceInsert) unset($this->changed['ID']);
$hasChanges = false;
foreach($this->changed as $fieldName => $changed) {
if($changed) {
$hasChanges = true;
break;
}
}
if($hasChanges || $forceWrite || !$this->record['ID']) {
// New records have their insert into the base data table done first, so that they can pass the
// generated primary key on to the rest of the manipulation
$baseTable = $ancestry[0];
if((!isset($this->record['ID']) || !$this->record['ID']) && isset($ancestry[0])) {
DB::query("INSERT INTO \"{$baseTable}\" (\"Created\") VALUES (" . DB::getConn()->now() . ")");
$this->record['ID'] = DB::getGeneratedID($baseTable);
$this->changed['ID'] = 2;
$isNewRecord = true;
}
// Divvy up field saving into a number of database manipulations
$manipulation = array();
if(isset($ancestry) && is_array($ancestry)) {
foreach($ancestry as $idx => $class) {
$classSingleton = singleton($class);
foreach($this->record as $fieldName => $fieldValue) {
if(isset($this->changed[$fieldName]) && $this->changed[$fieldName] && $fieldType = $classSingleton->hasOwnTableDatabaseField($fieldName)) {
$fieldObj = $this->dbObject($fieldName);
if(!isset($manipulation[$class])) $manipulation[$class] = array();
// if database column doesn't correlate to a DBField instance...
if(!$fieldObj) {
$fieldObj = DBField::create('Varchar', $this->record[$fieldName], $fieldName);
}
// Both CompositeDBFields and regular fields need to be repopulated
$fieldObj->setValue($this->record[$fieldName], $this->record);
if($class != $baseTable || $fieldName!='ID')
$fieldObj->writeToManipulation($manipulation[$class]);
}
}
// Add the class name to the base object
if($idx == 0) {
$manipulation[$class]['fields']["LastEdited"] = "'".SS_Datetime::now()->Rfc2822()."'";
if($dbCommand == 'insert') {
$manipulation[$class]['fields']["Created"] = "'".SS_Datetime::now()->Rfc2822()."'";
//echo "<li>$this->class - " .get_class($this);
$manipulation[$class]['fields']["ClassName"] = "'$this->class'";
}
}
// In cases where there are no fields, this 'stub' will get picked up on
if(self::has_own_table($class)) {
$manipulation[$class]['command'] = $dbCommand;
$manipulation[$class]['id'] = $this->record['ID'];
} else {
unset($manipulation[$class]);
}
}
}
$this->extend('augmentWrite', $manipulation);
// New records have their insert into the base data table done first, so that they can pass the
// generated ID on to the rest of the manipulation
if(isset($isNewRecord) && $isNewRecord && isset($manipulation[$baseTable])) {
$manipulation[$baseTable]['command'] = 'update';
}
DB::manipulate($manipulation);
if(isset($isNewRecord) && $isNewRecord) {
DataObjectLog::addedObject($this);
} else {
DataObjectLog::changedObject($this);
}
$this->onAfterWrite();
$this->changed = null;
} elseif ( $showDebug ) {
echo "<b>Debug:</b> no changes for DataObject<br />";
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
}
// Clears the cache for this object so get_one returns the correct object.
$this->flushCache();
if(!isset($this->record['Created'])) {
$this->record['Created'] = SS_Datetime::now()->Rfc2822();
}
$this->record['LastEdited'] = SS_Datetime::now()->Rfc2822();
} else {
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
}
// Write ComponentSets as necessary
if($writeComponents) {
$this->writeComponents(true);
}
return $this->record['ID'];
}
Look at the $this->onAfterWrite();
It probably goes to my own function on NewsArticle.php and there starts the loop! I'm not sure though, so i could need some help!!
Does anyone knows how to use the doPublish() function?
The reason that is happening is that in the DataObjectAsPage::publish() method, it is calling ->write() - line 11 of your 3rd code sample.
So what happens is it calls ->write(), at the end of ->write() your onAfterWrite() method is called, which calls publish(), which calls write() again.
If you remove the onAfterWrite() function that you've added, it should work as expected.
The doPublish() method on DataObjectAsPage will take care of publishing from Stage to Live for you.