Skip to main content
Looking for Correct Changes Started by ahrasis · · Read 5726 times 0 Members and 1 Guest are viewing this topic. previous topic - next topic

Looking for Correct Changes

I am trying to configure the changes needed in mesfa addon. In 1.0.9, we made changes to Db-mysql.class.php from:
Code: [Select]
$db_callback = array($db_values, $connection === null ? $this->_connection : $connection);
to:
Code: [Select]
$db_callback = array($db_string, $db_values, $connection === null ? $this->_connection : $connection);

However, the code in 1.1 Beta 3 is moved to Db-abstract.class.php :
Code: [Select]
	public function quote($db_string, $db_values, $connection = null)
{
// Only bother if there's something to replace.
if (strpos($db_string, '{') !== false)
{
// This is needed by the callback function.
$this->_db_callback_values = $db_values;
if ($connection === null)
{
$this->_db_callback_connection = $this->_connection;
}
else
{
$this->_db_callback_connection = $connection;
}

I was thinking to change part of it (as below) but it causes long loop and thus, page error 500:
Code: [Select]
$this->_db_callback_values = array($db_string, $db_values);

What is the correct changes I need to do?

Re: Looking for Correct Changes

Reply #1

Would you mind to remind me which one is mesfa and why you need to change the db quoting function? O:-)
Bugs creator.
Features destroyer.
Template killer.


Re: Looking for Correct Changes

Reply #3

I think it is better for me to list the code we changed for database files in 1.0 so that the equivalent in 1.1 may be seen and advised as a whole.

Currently the addon do work without the changes but the said changes are needed for limiting the displayed boards, topics and posts.

I will be out Friday prayer and will post them all after that.

Re: Looking for Correct Changes

Reply #4

I'm pretty sure you will not like the answer I'm going to give you, but that's how I would try to do it (provided I didn't test the code so tit may not work as expected...).

Two new files, one called Db-mysqlm.class.php, while the other Db-postgresql.class.php in /sources/database/
The two containing a slightly modified version of the database class, for example, for the mysql one:
Code: [Select]
<?php

// Let's define the name of the class so that we will be able to use it in the instantiations
if (!defined('DB_TYPE'))
define('DB_TYPE', 'MySQLm');

/**
 * SQL database class, implements database class to control mysql functions
 */
class Database_MySQLm extends Database_MySQL
{
protected static $_string = '';

public static function initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options = array())
{
// Initialize the instance... if not done already!
if (self::$_db === null)
self::$_db = new self();

return parent::initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options);
}

public function query($identifier, $db_string, $db_values = array(), $connection = null)
{
$this->_string = $db_string;

$return = parent::query($identifier, $db_string, $db_values, $connection);

$this->_string = '';

return $return;
}

public function quote($db_string, $db_values, $connection = null)
{
$this->_string = $db_string;

$return = parent::quote($db_string, $db_values, $connection);

$this->_string = $db_string;

return $return;
}
public function replacement__callback($matches)
{
global $user_info, $db_prefix, $modSettings;

// Connection gone???  This should *never* happen at this point, yet it does :'(
if (!$this->validConnection($this->_db_callback_connection))
Errors::instance()->display_db_error();

// if in subforum add find_in_set(id_board or id_cat)
if ($matches[1] === 'query_see_board')
{
preg_match('/([a-zA-Z\.]+(id_cat|id_board)).?/is', $this->_string, $cols);
if(!empty($modSettings['subforums'][$_SERVER['SERVER_NAME']]) && isset($cols[2]))
return $user_info['query_see_board'] .' AND FIND_IN_SET('. $cols[1] .', \''. ($cols[2] == 'id_cat' ? $modSettings['subforums'][$_SERVER['SERVER_NAME']]['cats'] : $modSettings['subforums'][$_SERVER['SERVER_NAME']]['boards']) .'\') != 0';
else
return $user_info['query_see_board'];
}

// if in subforum add find_in_set(id_board or id_cat)
if ($matches[1] === 'query_wanna_see_board')
{
preg_match('/([a-zA-Z\.]+(id_cat|id_board)).?/is', $this->_string, $cols);
if(!empty($modSettings['subforums'][$_SERVER['SERVER_NAME']]) && isset($cols[2]))
return $user_info['query_wanna_see_board'] .' AND FIND_IN_SET('. $cols[1] .', \''. ($cols[2] == 'id_cat' ? $modSettings['subforums'][$_SERVER['SERVER_NAME']]['cats'] : $modSettings['subforums'][$_SERVER['SERVER_NAME']]['boards']) .'\') != 0';
else
return $user_info['query_wanna_see_board'];
}

// special tag.. add find_in_set(...)
if ($matches[1] === 'subforums_see_board')
{
if(!empty($modSettings['subforums'][$_SERVER['SERVER_NAME']]) && isset($matches[2]))
return ' AND FIND_IN_SET('. str_replace('-', '.', $matches[2]) .', \''. $modSettings['subforums'][$_SERVER['SERVER_NAME']]['boards'] .'\') != 0';
else
return '';
}

return parent::replacement__callback($matches);
}
}

I think this would do.
The only caveat is you'd need to change the database type both at install and uninstall with something like that:
Code: [Select]
// Installing
$settingsForm = new Settings_Form(Settings_Form::FILE_ADAPTER);
$settingsForm->setConfigValues(array('db_type' => 'MySQLm');
$settingsForm->save();

// Uninstalling
$settingsForm = new Settings_Form(Settings_Form::FILE_ADAPTER);
$settingsForm->setConfigValues(array('db_type' => 'MySQL');
$settingsForm->save();

Later I'll see what can be done about you "classic" way. Most likely it will not differ much, just change the replacement__callback method  accept two arguments?
Bugs creator.
Features destroyer.
Template killer.

Re: Looking for Correct Changes

Reply #5

Actually, I love it because it extends the original file with other file rather than modifying it. Currently in 1.0 branch, we modify as follows:
Code: [Select]
<file name="SOURCEDIR/database/Db-mysql.class.php">
<operation>
<search position="replace"><![CDATA[
public static function initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options = array())
{
global $mysql_set_mode;

]]></search>
<add><![CDATA[
public static function initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options = array())
{
global $mysql_set_mode;

// include SubForums DB functions
include_once(ADMINDIR .'/SubForums/Subforums-DB.php');
]]></add>
</operation>

<operation>
<search position="replace"><![CDATA[
public function replacement__callback($matches)
{
global $db_callback, $user_info, $db_prefix;

list ($values, $connection) = $db_callback;

// Connection gone???  This should *never* happen at this point, yet it does :'(
if (!is_object($connection))
display_db_error();

if ($matches[1] === 'db_prefix')
return $db_prefix;

if ($matches[1] === 'query_see_board')
return $user_info['query_see_board'];

if ($matches[1] === 'query_wanna_see_board')
return $user_info['query_wanna_see_board'];
]]></search>
<add><![CDATA[
public function replacement__callback($matches)
{
global $db_callback, $user_info, $db_prefix;

list ($query, $values, $connection) = $db_callback;

// subforums db_callback.
if(($subvar = SubForums_dbcallback($matches, $query)) !== null)
return $subvar;
]]></add>
</operation>

<operation>
<search position="replace"><![CDATA[
// Only bother if there's something to replace.
if (strpos($db_string, '{') !== false)
{
// This is needed by the callback function.
$db_callback = array($db_values, $connection === null ? $this->_connection : $connection);
]]></search>
<add><![CDATA[
// Only bother if there's something to replace.
if (strpos($db_string, '{') !== false)
{
// This is needed by the callback function.
$db_callback = array($db_string, $db_values, $connection === null ? $this->_connection : $connection);
]]></add>
</operation>

<operation>
<search position="replace"><![CDATA[
if (empty($db_values['security_override']) && (!empty($db_values) || strpos($db_string, '{db_prefix}') !== false))
{
// Pass some values to the global space for use in the callback function.
$db_callback = array($db_values, $connection);
]]></search>
<add><![CDATA[
if (empty($db_values['security_override']) && (!empty($db_values) || strpos($db_string, '{db_prefix}') !== false))
{
// Pass some values to the global space for use in the callback function.
$db_callback = array($db_string, $db_values, $connection);
]]></add>
</operation>
</file>

<file name="SOURCEDIR/database/Db-postgresql.class.php">
<operation>
<search position="replace"><![CDATA[
public static function initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options = array())
{
]]></search>
<add><![CDATA[
public static function initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options = array())
{

include_once(ADMINDIR .'/SubForums/Subforums-DB.php');
]]></add>
</operation>

<operation>
<search position="replace"><![CDATA[
public function replacement__callback($matches)
{
global $db_callback, $user_info, $db_prefix;

list ($values, $connection) = $db_callback;

// Connection gone?
if (!is_resource($connection))
display_db_error();

if ($matches[1] === 'db_prefix')
return $db_prefix;

if ($matches[1] === 'query_see_board')
return $user_info['query_see_board'];

if ($matches[1] === 'query_wanna_see_board')
return $user_info['query_wanna_see_board'];
]]></search>
<add><![CDATA[
public function replacement__callback($matches)
{
global $db_callback, $user_info, $db_prefix;

list ($query, $values, $connection) = $db_callback;

// call the subforums db_callback.
if(($subvar = SubForums_dbcallback($matches, $query)) !== null)
return $subvar;
]]></add>
</operation>

<operation>
<search position="replace"><![CDATA[
// Only bother if there's something to replace.
if (strpos($db_string, '{') !== false)
{
// This is needed by the callback function.
$db_callback = array($db_values, $connection === null ? $this->_connection : $connection);
]]></search>
<add><![CDATA[
// Only bother if there's something to replace.
if (strpos($db_string, '{') !== false)
{
// This is needed by the callback function.
$db_callback = array($db_string, $db_values, $connection === null ? $this->_connection : $connection);
]]></add>
</operation>

<operation>
<search position="replace"><![CDATA[
if (empty($db_values['security_override']) && (!empty($db_values) || strpos($db_string, '{db_prefix}') !== false))
{
// Pass some values to the global space for use in the callback function.
$db_callback = array($db_values, $connection);
]]></search>
<add><![CDATA[
if (empty($db_values['security_override']) && (!empty($db_values) || strpos($db_string, '{db_prefix}') !== false))
{
// Pass some values to the global space for use in the callback function.
$db_callback = array($db_string, $db_values, $connection);
]]></add>
</operation>
</file>
I will test this first, soonest.

Questions:
1. Can most of core files be extended and overwritten like that?
2. Can I used that similar method instead of using manual modification (currently being used)?

Re: Looking for Correct Changes

Reply #6

Quote from: ahrasis – Actually, I love it because it extends the original file with other file rather than modifying it.
Glad you like it, I thought you wouldn't be much happy because is a bit more complex here and there. :)

Quote from: ahrasis – 1. Can most of core files be extended and overwritten like that?
Of course, all classes can be extended.
That said, in the current state of 1.0 and partially 1.1, only a part of the code can be expanded this way, and anyway, the trick I used above is kind of tricky because if another addon has to change the class it would break your code. I suggested it because as far as I know, yours is the only case that require to change the database functions and as such it is acceptable, but remember it may not always work.
In the future, it would probably be wise to take in consideration this kind of features as well.

Quote from: ahrasis – 2. Can I used that similar method instead of using manual modification (currently being used)?
In 1.0 is slightly trickier I think, I'm not sure I would recommend it.
Bugs creator.
Features destroyer.
Template killer.

Re: Looking for Correct Changes

Reply #7

Quote from: emanuele –
Code: [Select]
// Installing
$settingsForm = new Settings_Form(Settings_Form::FILE_ADAPTER);
$settingsForm->setConfigValues(array('db_type' => 'MySQLm');
$settingsForm->save();

// Uninstalling
$settingsForm = new Settings_Form(Settings_Form::FILE_ADAPTER);
$settingsForm->setConfigValues(array('db_type' => 'MySQL');
$settingsForm->save();
How do I run this code at install and uninstall again? Thank you.

Re: Looking for Correct Changes

Reply #8

IIRC you have an install.php and an uninstall.php in he package, or not?
Just add it to them (the first part to install.php and the second to uninstall.php, obviously).

Oh, wait, I forgot you'd have to create also a:
Code: (DbSearch-mysqlm.php) [Select]
<?php

/**
 * MySQL implementation of DbSearch
 */
class DbSearch_MySQLm extends DbSearch_MySQL
{
}

and a:
Code: (DbTable-mysql.php) [Select]
<?php

class DbTable_MySQLm extends DbTable_MySQL
{
}
empty classes are just fine because you don't need to redefine anything of those classes. :)

And of course the corresponding versions for PostgreSQL. :)
Bugs creator.
Features destroyer.
Template killer.

Re: Looking for Correct Changes

Reply #9

I end up creating install.php and remove.php for the said code (run as code), after creating the three MySQLm files.
Code: [Select]
<?php

$settingsForm = new Settings_Form(Settings_Form::FILE_ADAPTER);
$settingsForm->setConfigValues(array('db_type' => 'MySQLm');
$settingsForm->save();

?>

It causes temporary 500 error after I click install (action=admin;area=packages;sa=install2;package=MultiTenancy11.b305.elkarte.ahrasis.com.zip;pid=0) and when refresh, the page comes back with this warning:
QuoteAn Error Has Occurred
Your session timed out while posting. Please go back and try again.

The installation did work without that install.php.

Re: Looking for Correct Changes

Reply #10

Typo on my side?
Code: [Select]
$settingsForm->setConfigValues(array('db_type' => 'MySQLm'));
See the two parenthesis closed at the end of the statement instead of the single one above? (And same for the uninstall.)

Never mind, it won't work.
Last Edit: November 07, 2016, 02:10:16 pm by emanuele
Bugs creator.
Features destroyer.
Template killer.

Re: Looking for Correct Changes

Reply #11

Oo.. ok. Noted that. Any other way that I should try to convert the following modification?
Quote from: ahrasis –
Code: [Select]
<file name="SOURCEDIR/database/Db-mysql.class.php">
<operation>
<search position="replace"><![CDATA[
public static function initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options = array())
{
global $mysql_set_mode;

]]></search>
<add><![CDATA[
public static function initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options = array())
{
global $mysql_set_mode;

// include SubForums DB functions
include_once(ADMINDIR .'/SubForums/Subforums-DB.php');
]]></add>
</operation>

<operation>
<search position="replace"><![CDATA[
public function replacement__callback($matches)
{
global $db_callback, $user_info, $db_prefix;

list ($values, $connection) = $db_callback;

// Connection gone???  This should *never* happen at this point, yet it does :'(
if (!is_object($connection))
display_db_error();

if ($matches[1] === 'db_prefix')
return $db_prefix;

if ($matches[1] === 'query_see_board')
return $user_info['query_see_board'];

if ($matches[1] === 'query_wanna_see_board')
return $user_info['query_wanna_see_board'];
]]></search>
<add><![CDATA[
public function replacement__callback($matches)
{
global $db_callback, $user_info, $db_prefix;

list ($query, $values, $connection) = $db_callback;

// subforums db_callback.
if(($subvar = SubForums_dbcallback($matches, $query)) !== null)
return $subvar;
]]></add>
</operation>

<operation>
<search position="replace"><![CDATA[
// Only bother if there's something to replace.
if (strpos($db_string, '{') !== false)
{
// This is needed by the callback function.
$db_callback = array($db_values, $connection === null ? $this->_connection : $connection);
]]></search>
<add><![CDATA[
// Only bother if there's something to replace.
if (strpos($db_string, '{') !== false)
{
// This is needed by the callback function.
$db_callback = array($db_string, $db_values, $connection === null ? $this->_connection : $connection);
]]></add>
</operation>

<operation>
<search position="replace"><![CDATA[
if (empty($db_values['security_override']) && (!empty($db_values) || strpos($db_string, '{db_prefix}') !== false))
{
// Pass some values to the global space for use in the callback function.
$db_callback = array($db_values, $connection);
]]></search>
<add><![CDATA[
if (empty($db_values['security_override']) && (!empty($db_values) || strpos($db_string, '{db_prefix}') !== false))
{
// Pass some values to the global space for use in the callback function.
$db_callback = array($db_string, $db_values, $connection);
]]></add>
</operation>
</file>

<file name="SOURCEDIR/database/Db-postgresql.class.php">
<operation>
<search position="replace"><![CDATA[
public static function initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options = array())
{
]]></search>
<add><![CDATA[
public static function initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options = array())
{

include_once(ADMINDIR .'/SubForums/Subforums-DB.php');
]]></add>
</operation>

<operation>
<search position="replace"><![CDATA[
public function replacement__callback($matches)
{
global $db_callback, $user_info, $db_prefix;

list ($values, $connection) = $db_callback;

// Connection gone?
if (!is_resource($connection))
display_db_error();

if ($matches[1] === 'db_prefix')
return $db_prefix;

if ($matches[1] === 'query_see_board')
return $user_info['query_see_board'];

if ($matches[1] === 'query_wanna_see_board')
return $user_info['query_wanna_see_board'];
]]></search>
<add><![CDATA[
public function replacement__callback($matches)
{
global $db_callback, $user_info, $db_prefix;

list ($query, $values, $connection) = $db_callback;

// call the subforums db_callback.
if(($subvar = SubForums_dbcallback($matches, $query)) !== null)
return $subvar;
]]></add>
</operation>

<operation>
<search position="replace"><![CDATA[
// Only bother if there's something to replace.
if (strpos($db_string, '{') !== false)
{
// This is needed by the callback function.
$db_callback = array($db_values, $connection === null ? $this->_connection : $connection);
]]></search>
<add><![CDATA[
// Only bother if there's something to replace.
if (strpos($db_string, '{') !== false)
{
// This is needed by the callback function.
$db_callback = array($db_string, $db_values, $connection === null ? $this->_connection : $connection);
]]></add>
</operation>

<operation>
<search position="replace"><![CDATA[
if (empty($db_values['security_override']) && (!empty($db_values) || strpos($db_string, '{db_prefix}') !== false))
{
// Pass some values to the global space for use in the callback function.
$db_callback = array($db_values, $connection);
]]></search>
<add><![CDATA[
if (empty($db_values['security_override']) && (!empty($db_values) || strpos($db_string, '{db_prefix}') !== false))
{
// Pass some values to the global space for use in the callback function.
$db_callback = array($db_string, $db_values, $connection);
]]></add>
</operation>
</file>

Re: Looking for Correct Changes

Reply #12

If I got it right you basically need $db_string in the replacement__callback.
If so, add to the abstract class a new property (similarly to what I did above, but editing the abstract Database_Abstract class file), then, in query and quote (similarly to what I did above) you assign the string to this new property[1].

So you will add a :
Code: [Select]
protected $_db_string;
to the Database_Abstract.
Then, in each of the database classes (either the abstract of the dbms-specific depending where the methods exist), in quote and query, you'll add before the call of replacement__callback something like:
Code: [Select]
$this->_db_string = $db_string;
and after replacement__callback:
Code: [Select]
$this->_db_string = '';
just to be sure things are cleaned up.
And so on.
Property is the name of variables when are "part" of a class, so the $this->something, the "something" is a property. Instead, if it is a function, it's called a method.
Bugs creator.
Features destroyer.
Template killer.

Re: Looking for Correct Changes

Reply #13

I have to note this as unfinished so that I won't forget to get it working when I have free time.