Returning results from a custom MediaWiki hook - php

I'm hacking an existing MediaWiki extension, ProcessCite, that adds a custom hook to the Cite extension. Since migrating to PHP 5.4 and MW 1.22 (from PHP 5.3 and MW 1.19.2), the extension does not appear to work correctly. The problem is with the custom hook not returning the data it should do.
Here are the relevant parts of the code:
ProcessCite.php
# Declare the hook:
$wgHooks['CiteBeforeStackEntry'][] = 'wfProcessCite';
# the function itself
function wfProcessCite($str, $argv){
# process $argv and $str to create a new version of $str
# $argv remains unchanged, $str is set to new value
...
$str = "new string";
return true;
}
in Cite_body.php
function stack( $str, $key = null, $group, $follow, $call ) {
# add the call to the CiteBeforeStackEntry hook
wfRunHooks( 'CiteBeforeStackEntry', array( &$str, &$call ) );
I've added debugging statements to the beginning and end of wfProcessCite, which show that $str is being altered; however, debug statements before and after wfRunHooksshow no change to $str.
Can anyone help?

Got the answer from Andru Vallance on the Mediawiki mailing list:
Prepending the function argument with an ampersand character causes it to be passed it in by reference.
That means you are directly manipulating the original variable inside your function, rather than a copy.
function wfProcessCite( &$str, $argv ){
$str = ‘new value’;
return true;

Related

How to get a function name when I hooked it in a php extension

I tried to write a PHP module which is used to detect zend internal function which is called in a php cgi file. Liked code shown below,I want get its name -- 'printf' in my code.
<?php printf("Hello SO!");?>
Now I hooked this function with a function named 'zend_set_user_opcode_handler'.However,I am not able to get the function name which was hooked.(It is 'printf' in this example.) So, what should I do if I want achieve that 'printf' in Function hook_handler()?
Codes here.
int shellhook_handler(ZEND_OPCODE_HANDLER_ARGS){
/* What should I do to catch function name here*/
return ZEND_USER_OPCODE_DISPATCH;
}
PHP_MINIT_FUNCTION(shellhook)
{
REGISTER_INI_ENTRIES();
zend_set_user_opcode_handler(ZEND_DO_FCALL, hook_handler);
return SUCCESS;
}
Hey guys I have got the answer. There are two different methods to achieve hooked function's name.
First, if PHP5 is used, a defining of macro is necessary,because the method depend on the PHP minor version(less than 4 or not).
#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 4)
# define OP1_CONSTANT_PTR(n) (&(n)->op1.u.constant)
#else
# define OP1_CONSTANT_PTR(n) ((n)->op1.zv)
#endif
zend_op *opline = execute_data->opline;
zval *fname = OP1_CONSTANT_PTR(opline);
php_printf("FunctionName:%s\n",Z_STRVAL_P(fname));
Second, if PHP7 is used, parameters of shellhook() are not ZEND_OPCODE_HANDLER_ARGS any more. It is replaced by zend_execute_data *execute_data.
zend_execute_data *call = execute_data->call;
zend_function *fbc = call->func;
zend_string *fname = fbc->common.function_name;
php_printf("FunctionName:%s\n",ZSTR_VAL(fname));

How to submit an outside variable to Gravity Forms through WP filter

This type of work is new to me, so please be patient if the answer is something easy.
I'm using Wordpress and Gravity Forms on my site, and I want to pre-populate the form with data from an object (the object comes from an API, so I can't just use wordpress current_user object).
How can I use an outside variable inside a wordpress filter?
For Example:
$fname = $object->first_name;
add_filter('gform_field_value_firstname', *Populate the field with $fname*);
The below is the normal usage of the function, from Gravity Forms Docs (http://www.gravityhelp.com/documentation/page/Gform_field_value_$parameter_name)
add_filter('gform_field_value_firstname', "dothis");
Where "dothis" points to a function.
The below also works (based on this excellent article: http://www.doitwithwp.com/pre-populate-fields-using-gravity-forms/):
add_filter('gform_field_value_firstname', create_function("", 'return "John";' ));
However, I can't figure out how to get it to accept an outside variable also. For example, I'd like to do:
$fname = $object->first_name;
add_filter('gform_field_value_firstname', create_function("", 'return $fname;' ));
But php tells me that fname is an undefined variable.
I've reviewed this thread PHP: How to make variable visible in create_function()? , but I could not get the Closure solutions to work. I have PHP Version 5.2.17.
Would you please post an example of how to do this correctly?
Make $fname a global variable and you can reference it in your create_function as a global.
global $fname = $object->first_name;
add_filter( 'gform_field_value_firstname', create_function( '', 'global $fname; return $fname;' ) );
However if you have multiple values to return, it's better to make $object global:
global $object;
add_filter( 'gform_field_value_firstname', create_function( '', 'global $object; return
$object->first_name;' ));
add_filter( 'gform_field_value_lastname', create_function( '', 'global $object; return $object->last_name;' ));
And so on...

preg_replace not retrieving correct data

I'm using my own cms from scratch, so, i'm adding useful functions for my system, but i got stuck on this:
A phrase is being loaded from lang file on array, in this case, $lang['sign']['server'] = 'Sign in with your {{servername}} registered account:';, and then, by a function, {{servername}} must be replaced by $config['servername'].
What i have so far on my functions class is the following:
public function replaceTags($text)
{
global $config;
return preg_replace("/{{(.*?)}}/" , $config[strtolower("$1")], $text) ;
}
Im calling this function here: $main->set('ssocial', $FUNC->replaceTags($lang['sign']['social']));, but the result is Sign in with your registered account: instead of Sign in with your "Server Name Goes Here" registered account.
Any ideas about why the preg_replace is not retrieving the value?
Also, when $config[”$1”] is inside '' like this '$config[”$1”]', the output is Sign in with your $config[”servername”] registered account:, so i have no clues about what's wrong.
Thanks in advance.
This is a quick and dirty working example using preg_replace_callback
<?php
$config = array('server' => 'my custom text');
function handler($matches){
global $config;
return $config[$matches[1]];
}
function replaceTags($text)
{
return preg_replace_callback("/{{(.*?)}}/" , 'handler', $text) ;
}
print replaceTags("Hello {{server}}");
Output:
Hello my custom text
As for why your code doesn't work: the second parameter of preg_replace is $config[strtolower("$1")], so php will literally look for key "$1" in $config, which probably doesn't exist.

Mediawiki parser and recursiveTagParse

I have an issue with rendering wikitext in hook for tag processing.
public static function onTagRender( $input, array $args, $parser, $frame ) {
...
$text = $parser->recursiveTagParse($sometext, $frame);
...
return $text;
}
If $sometext contains e.g.
"Example from page [[XYZ]]"
then I expect returned $text should contain
"Example from page XYZ"
But I get only
"Example from page <!--LINK 0:0-->"
I have tried also $parser->replaceInternalLinks(), but with same result. What have I overlooked?
If some people run into the same problem, try calling replaceLinkHolders after recursiveTagParse. (I didn't have the same problem so I didn't test it.)
So in OP's code snippet, that would be:
public static function onTagRender( $input, array $args, $parser, $frame ) {
...
$text = $parser->recursiveTagParse($sometext, $frame);
$text = $parser->replaceLinkHolders($text);
...
return $text;
}
Explanation according to my understanding:
Actually, the usual parse method calls the internalParse method -- which does most of the job -- and then do some other stuff. On the other hand, recursiveTagParse is almost only calling internalParse, so it doesn't execute the other stuff from parse.
Problem is, links are parsed in two steps:
Links are first extracted into LinkHolderArray and they are replaced with <!--LINK $ns:$key--> in the text.
(This is done by replaceInternalLinks, called by internalParse, so that's fine.)
Then <!--LINK $ns:$key--> markers are parsed into HTML links.
(This is done by replaceLinkHolders which is called by parse, not by internalParse, and thus not by recursiveTagParse.)
Parser::recursiveTagParse only do partial rendering, afaik. That may or may not be the problem. To fully render any user input, you will have to create a parser function (http://www.mediawiki.org/wiki/Manual:Parser_functions) instead of a tag function.
See http://www.mediawiki.org/wiki/Manual:Tag_extensions#How_do_I_render_wikitext_in_my_extension.3F

PHP Hook Function

Can I basically do something like:
register_function_hook('myFunctionHook');
so then when any function is run:
functionA(); //The hook runs myFunctionHook();
anoterFunction(); //The hook runs myFunctionHook();
Class::functionA(); //The hook runs myFunctionHook();
Does such a thing exist?
-- Edit --
What I want to do is to get a breakdown of durations of each function. Ie. Performance Tuning. I want to get an idea of what takes all the time without installing xDebug on my Apache server, however I don't know if it is possible.
It's possible with register_tick_function(), also check this comment on the PHP manual:
$script_stats = array();
$time = microtime(true);
function track_stats(){
global $script_stats,$time;
$trace = debug_backtrace();
$exe_time = (microtime(true) - $time) * 1000;
$func_args = implode(", ",$trace[1]["args"]);
$script_stats[] = array(
"current_time" => microtime(true),
"memory" => memory_get_usage(true),
"file" => $trace[1]["file"].': '.$trace[1]["line"],
"function" => $trace[1]["function"].'('.$func_args.')',
"called_by" => $trace[2]["function"].' in '.$trace[2]["file"].': '.$trace[2]["line"],
"ns" => $exe_time
);
$time = microtime(true);
}
declare(ticks = 1);
register_tick_function("track_stats");
// the rest of your project code
// output $script_stats into a html table or something
This "hooks" to everything, not just functions but I think it fits your purpose.
No, its not possible the way you like
But You can achieve something close with inheritance.
class Vehicle {
function __construct() {
$this->hookFunction();
}
function hookFunction() {
//
}
}
class Car extends Vehicle {
}
Class Toyota extends Car {
}
new Toyota(); // will you hook function
// this exclude static call to member functions, or other inline functions.
What you looking for is called profiler. And PQP looks like one, which is standalone.
Instead of polluting the code, you should use a real Profiler, like that one provided by xdebug
Not sure if the Topic Starter needs this anymore, but perhaps others can still benefit from this.
There is a PHP lib, written completely in PHP, that allows you to do exactly what you want.
Here's an article about how it works, including the source code:
http://phpmyweb.net/2012/04/26/write-an-awesome-plugin-system-in-php/
It allows you to register a function from a class to be hooked. So it basically executes your code first, and then you determine wether you want to call the original function too after your code has been executed.

Categories