MongooseIM module not getting variables from Packet - php

I wrote the following module for MongooseIM but nothing is posted to the PHP file.
start(_Host, _Opt) ->
inets:start(),
ejabberd_hooks:add(user_send_packet, _Host, ?MODULE, fetchPacketData, 50).
stop (_Host) ->
ejabberd_hooks:delete(user_send_packet, _Host, ?MODULE, fetchPacketData, 50).
fetchPacketData(_From, _To, Packet) ->
To = xml:get_tag_attr_s(<<"to">>, Packet),
httpc:request(post, {"http://example.com/receiver.php",[],
"application/x-www-form-urlencoded",
lists:concat(["To=",To,"&Type=1","&Body=ABC"])}, [], []).
I was able to successfully implement the module after following erszcz's suggestion(Please see below). Below is the code i used. Hope it helps someone else too :)
start(Host, _Opts)->
inets:start(),
ejabberd_hooks:add(user_send_packet, Host, ?MODULE, sendMessage, 50),
ok.
stop(Host)->
ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, sendMessage, 50),
ok.
sendMessage(_From, _To, Packet) ->
case xml:get_tag_attr_s(<<"type">>, Packet) of
<<"chat">> ->
To = lists:flatten(io_lib:format("~s", [xml:get_tag_attr_s(<<"to">>, Packet)])),
** post variables to PHP file using httpc:request **
ok;
_ ->
ok
end.

offline_message_hook is only called when the server is routing a message to a user who is not online. user_send_packet is run every time the server receives a stanza from a client. This might explain why the handler is not run, though it depends on how you test. There's an article with one section describing some hooks in MongooseIM available on the official wiki.
As for problems with retrieving packet attributes, either logging the incoming packet for inspection or using dbg in the server Erlang shell to trace the actual calls done by your module might be the way to tell what's happening.
An example session with dbg debugging the problem might look like this:
(mongooseim#localhost)1> dbg:tracer().
{ok,<0.570.0>}
(mongooseim#localhost)2> dbg:p(all, call).
{ok,[{matched,mongooseim#localhost,279}]}
(mongooseim#localhost)3> dbg:tpl(mod_test, x).
{ok,[{matched,mongooseim#localhost,5},{saved,x}]}
(mongooseim#localhost)4> (<0.576.0>) call mod_test:fetchPacketData({jid,<<"alice">>,<<"localhost">>,<<"escalus-default-resource">>,<<"alice">>,
<<"localhost">>,<<"escalus-default-resource">>},{jid,<<"alice">>,<<"localhost">>,<<>>,<<"alice">>,<<"localhost">>,<<>>},{xmlel,<<"presence">>,[{<<"xml:lang">>,<<"en">>}],[]})
(<0.576.0>) exception_from {mod_test,fetchPacketData,3} {error,function_clause}
2015-03-15 11:46:03.028 [error] <0.576.0>#ejabberd_hooks:run1:240 {function_clause,[{lists,thing_to_list,[<<>>],[{file,"lists.erl"},{line,601}]},{lists,flatmap,2,[{file,"lists.erl"},{line,1248}]},{lists,flatmap,2,[{file,"lists.erl"},{line,1248}]},{mod_test,fetchPacketData,3,[{file,"src/mod_test.erl"},{line,15}]},{safely,apply,3,[{file,"src/safely.erl"},{line,19}]},{ejabberd_hooks,run1,3,[{file,"src/ejabberd_hooks.erl"},{line,236}]},{ejabberd_c2s,session_established2,2,[{file,"src/ejabberd_c2s.erl"},{line,1063}]},{p1_fsm_old,handle_msg,10,[{file,"src/p1_fsm_old.erl"},{line,542}]}]}
Running hook: {user_send_packet,[{jid,<<"alice">>,<<"localhost">>,<<"escalus-default-resource">>,<<"alice">>,<<"localhost">>,<<"escalus-default-resource">>},{jid,<<"alice">>,<<"localhost">>,<<>>,<<"alice">>,<<"localhost">>,<<>>},{xmlel,<<"presence">>,[{<<"xml:lang">>,<<"en">>}],[]}]}
Callback: mod_test:fetchPacketData
We see that the handler errors out with function_clause when calling lists:thing_to_list(<<>>). The empty binary is a result of xml:get_tag_attr_s/2 when the attribute asked for is not found. lists:thing_to_list/1 is called to convert each parameter of lists:concat/1 to a list, but it's not possible to convert an empty binary <<>> to a list, hence the crash.
Match on the result of xml:get_tag_attr_s/2 and craft your logic appropriately to each case: when the attribute is found and when it's not there.
I don't know how to start a module in dbg. I tried what you had shared above and I think you missed the 4th command which could be an example of how to initiate a module.
This is a raw dump of my console without any edits - I did not miss any part.
You don't "start a module in dbg." You simply start a module the usual way and then use dbg from the server shell.
What I did was I took your example code, put it into apps/ejabberd/src/mod_test.erl file and built a release. After that you can enable the module either in ejabberd.cfg of the release (look for the modules section and do it similarly as examples there show) or you can start the server in live mode with mongooseimctl live and start the module manually with gen_mod:start_module(<<"localhost">>, mod_test, []) (where <<"localhost">> is just an example XMPP domain - substitute your own suitable domain there).
When the module is running (can be checked with gen_mod:is_loaded(<<"your-xmpp-domain">>, mod_name_goes_here)) you have to enable dbg. This is shown in the listing I added previously. I won't delve into describing how to use dbg as a very good introduction is already available on StackOverflow.
an example of how to test if an attribute exists or not
case xml:get_tag_attr_s(<<"some-attribute">>, Packet) of
<<>> ->
%% attribute does not exist, as get_tag_attr_s returned the default value
ok;
<<"some-value">> ->
%% do something sensible with <<"some-value">>
ok
end
Alternatively, you can use exml which is also part of MongooseIM (but not original ejabberd) and is more explicit about not finding the attribute you ask for:
case exml_query:attr(Packet, <<"some-attribute">>) of
undefined ->
%% not found
ok;
<<"some-value">> ->
%% do something
...
end

Related

Readline completion tab extra space

I'm trying to set auto-complete for readline to enable a user to navigate through the filesystem directories when running a script through CLI.
I found out PHP has a function called readline_completion_function for this purpose but every time I hit tab to complete a word, it adds a space at the end.
readline_completion_function(function() {
return ['aaa', 'bbb', 'ccc'];
});
// Input a or b or c
readline('Add char and tab: ');
I've create fiddle for you to test this:
https://repl.it/#rmdev/Readline-Completion-Tab-Extra-Space
I saw on Python readline configs that there's a configuration called set_completer_delims to set a character to be apendend after tab is hit but in PHP there are only two configurations and none of them apply to the completer delims.
I also saw some posts referring to this as a known bug but it seems it has been fixed on most of the integrations although I don't see any reference to a fix for the PHP one.
Is there any way to remove this space?
I'm using PHP 7.2.12 on a Mac.

Python-CGI environment set-up?

I am doing a project in Natural Language Processing using nltk in python.
The block structure of project is as follows:
Interface (in php) ->
[NLP Engine] (in python) ->
API calls (in php) ->
Result (in php)
The input is supposed to go via GET method from PHP Interface to the Python Engine.
Background:
I have created a virtual host (url=/linguistics/) server using Easy-PHP Dev Server (Location=D:\Computational_Linguistics). I have enabled it so that it can execute Test.py so that when I type linguistics/Test.py, it executes.
Issue:
The basic CGI was successfully executed and I could see the output in Chrome. But as soon as I imported another module, it returned this error:
Server error!
The server encountered an internal error and was unable to complete your request.
Error message:
End of script output before headers: engine.py
If you think this is a server error, please contact the webmaster.
Error 500
linguistics
Apache/2.4.4 (Win32) PHP/5.5.0
When I do NOT import nltk (or any other non-standard package) it works.
I did do the websearch to find the solution, and came to know I have to setup some environment variables to make it work.
But, I can not figure out how.
My code:
#!C:/Python27/python.exe
import nltk
from nltk import *
import re
import cgi, cgitb
inpt=cgi.FieldStorage()
str_in = inpt.getvalue('query')
def is_noun (str):
tags=nltk.pos_tag(nltk.word_tokenize(str))
for i in tags:
if i[1][1]=='N' or i[1][1]=='V': #Finding out the Nouns and the Verbs.
print "<h5>%s is a noun.<h5>" %i[0]
is_noun(str_in)
print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Hello - Second CGI Program</title>"
print "</head>"
print "<body>"
is_noun(str_in)
print "</body>"
print "</html>"
Since I received no answers (Not blaming anyone!) I read more documentations. As I have described in my Problem statement above, only NLP engine is written in Python. And, the problem exists in CGI environment only.
Hence My solution:
I modified engine.py to recieve input as commanline arguments, and then process upon it. It returns the processed data (In a exact format) back to buffer stream.
I used exec() command in PHP to do so.
The project is on GitHub, so If anyone wants to have a look at it, he's most welcome!
PS: I still don't know the reason for that error. I am hell sure that all environment paths were correct. So I'd call this answer a work-around, rather than a solution.
PPS: I am answering my own question, so that If anybody have same problem, they might consider this work around.
The problem is that you run is_noun twice, and the first one before you sent any headers. Hence, the error.
Another problem is that str_in is str, but I think nltk.pos_tag expects unicode. that is you need to decode the str_in value (if you use any symbols outside plain ASCII. That is you should do it anyway, but you will notice only if there will be such a character in the input):
str_in = unicode(inpt.getfirst('query', ''), 'utf-8')
and then, when you print unicode, you will need to encode it back:
print "<h5>%s is a noun.<h5>" % i[0].encode('utf-8')
But, in its current form it might be looking garbled in the browser, because you need to notify the browser, that the charset is 'utf-8', that is you need to change the content-type header:
print "Content-Type: text/html; charset=utf-8"
print
P.S. Hopefully, this is all for local use only and not available from the internet, because this should be much more complicated.

Get windows title using php doesn't work on browser call

My problem is I need to fetch FOOBAR2000's title because that including information of playing file, so I create a execute file via Win32 API(GetWindowText(), EnumWindows()) and it's working good.
TCHAR SearchText[MAX_LOADSTRING] = _T("foobar2000");
BOOL CALLBACK WorkerProc(HWND hwnd, LPARAM lParam)
{
TCHAR buffer[MAX_TITLESTRING];
GetWindowText(hwnd, buffer, MAX_TITLESTRING);
if(_tcsstr(buffer, SearchText))
{
// find it output something
}
return TRUE;
}
EnumWindows(WorkerProc, NULL);
Output would look like "album artis title .... [foobar2000 v1.1.5]"
I created a php file like test.php, and use exec() to execute it.
exec("foobar.exe");
then in console(cmd) I use command to execute it
php test.php
It's working good too, same output like before.
Now I use browser(firefox) to call this php file(test.php), strange things happened.
The output only foobar2000 v1.1.5, others information gone ...
I think maybe is exec() problem? priority or some limitation, so I use C# to create a COM Object and register it, and rewrite php code
$mydll = new COM("FOOBAR_COMObject.FOOBAR_Class");
echo $mydll->GetFooBarTitle();
still same result, command line OK, but browser Fail.
My question is
Why have 2 different output between command line and browser. I can't figure it out.
How can I get correct output via browser.
or there is a easy way to fetch FOOBAR2000's title?
Does anyone have experience on this problem?
== 2012/11/28 edited ==
follow Enno's opinion, I modify http_control plug-in to add filename info, original json info is "track title".
modify as following
state.cpp line 380 add 1 line
+pb_helper1 = pfc::string_filename(pb_item_ptr->get_path());
pb_helper1x = xml_friendly_string(pb_helper1);
# 1: when firefox opens the php and it gets executed, it the context depends on the user which runs the php-container (apache), this is quite different from the commandline call which gets executed in your context
# 2 and 3: there seems to be more than one way for getting the title: use the foobar-sdk and create a module which simply reads the current title per api, then write your result in an static-html-document inside your http-root-folder OR use the http-client inside the sdk, with it, you do not need a wabserver, even better use a already implemented module: for instance foo_upnp or foo-httpcontrol
Good luck!
If your webserver runs as a service, in windows you need to enable "allow desktop interaction" for the service. Your php script runs as a child of the webserver process when requested via browser.

Baffled: PHP Fatal error: Exception thrown without a stack frame in Unknown on line 0?

I have found that one common reason for the error is an exception being thrown from within an exception handler. I'm quite sure this doesn't happen in the application I'm trying to debug... But I've put all the initialization processing lines at the top of index.php in a try/catch.*
It can apparently also happen because some things cannot be serialized to be stored in a session. At most this application stores arrays into the session (quite a bit), but I'm confident that it doesn't store anything too out of the ordinary in it.
Someone commented that it happened to them because their primary key needed to be CHAR(32) instead of INT(11). The PK's in this app are all INTs.
Other suggestions are that it could be a problem with PHP 5.3.3 fixed in 5.3.6, full disk, and a need to typecast a SimpleXML value. We do happen to be running PHP 5.3.3, but upgrading would have to be a last resort in this case. It hasn't always been doing this.
UPDATE/NOTE: I actually can't reproduce the error myself, only see it happening in the logs, see below paragraph for where I believe the error is happening...
* From the error logs, it seems likely that at least one place it is happening is index.php. I am deducing this only because it is indicated in some entries by a referring URL. The try/catch code is currently only around the "top" initialization portion of the script, below that is mostly the HTML output. There is some PHP code in the output (pretty straightforward stuff though), so I may need to test that. Here is the catch part, which is not producing any output in the logs:
} catch (Exception $e) {
error_log(get_class($e)." thrown. Message: ".$e->getMessage(). " in " . $e->getFile() . " on line ".$e->getLine());
error_log('Exception trace stack: ' . print_r($e->getTrace(),1));
}
Would really appreciate any tips on this!
EDIT: PHP is running as an Apache module (Server API: Apache 2.0 Handler). I don't think there are any PHP accelerators in use, but it could just be that I don't know how to tell. None of the ones listed on Wikipedia are in phpinfo().
As far as I can tell the MPM is prefork. This is the first I'd ever looked into the MPM:
# ./httpd -l
Compiled in modules:
core.c
prefork.c
http_core.c
mod_so.c
The problem
In short you have a exception thrown somewhere, you have no idea where and up until now you could not reproduce the error: It only happens for some people, but not for you. You know that it happens for other people, because you see that in the error logs.
Reproduce the problem
Since you have already eliminated the common reasons you will need to reproduce the error. If you know which parameter will cause the error it should be easy to locate the error.
Most likely it is enough if you know all the POST/GET parameters.
If you can't reproduce with just these, you need to know additional request headers. Such as user agent, accept-encoding,...
If you still can't reproduce, then it becomes very difficult: The error may depend on a state (a session), the current time, the source ip address or the like.
The custom log method
Let's start simple: To get all parameters you can write in the very beginning of the affected php file something like:
file_put_contents("/path/to/some/custom_error_log", date()."\n".print_r(get_defined_vars(), true), FILE_APPEND | LOCK_EX);
Don't forget that the custom_error_log file must be writable to your php application. Then, when the error occurs in the error log, find the corresponding lines in your custom_error_log file. Hopefully there are not to many requests per second so that you can still identify the request. Maybe some additional parameters in the error log like source ip can help you identify the request (if your error log shows that).
From that data, reconstruct a request with the same POST/GET parameters.
The tcpdump method
The next option that is very simple as well, but requires you to have root-access on your target machine is to install tcpflow. Then create a folder, cd into that folder and simply execute (as root) tcpflow "port 80". The option (port 80) is a pcap filter expression. To see all you can do with that, see man pcap-filter. There is a lot what these filter expressions can do.
Now tcpflow will record all tcp connections on port 80, reconstruct the full data exchange by combining the packages belonging to one connection and dump this data to a file, creating two new files per connection, one for incoming data and one for outgoing data. Now find the files for a connection that caused an error, again based on the timestamp in your error log and by the last modified timestamp of the files. Then you get the full http request headers. You can now reconstruct the HTTP request completely, including setting the same accept-encoding, user-agent, etc. You can even pipe the request directly into netcat, replaying the exact request. Beware though that some arguments like a sessionid might be in your way. If php discovers that a session is expired you may just get a redirect to a login or something else that is unexpected. You may need to exchange things like the session id.
Mocking more things
If none of this helps and you can't reproduce the error on your machine, then you can try to mock everything that is hard to mock. For example the source ip adress. This might make some stunts necessary, but it is possible: You can connect to your server using ssh with the "-w" option, creating a tunnel interface. Then assign the offending ip adress to your own machine and set routes (route add host ) rules to use the tunnel for the specific ip. If you can cable the two computers directly together then you can even do it without the tunnel.
Don't foget to mock the session which should be esiest. You can read all session variables using the method with print_r(get_defined_vars()). Then you need to create a session with exactly the same variables.
Ask the user
Another option would be actually ask the user what he was doing. Maybe you can follow the same steps as he and can reproduce.
If none of this helps
If none of that helps... well... Then it gets seriously difficult. The IP-thing is already highly unlikely. It could be a GEO-IP library that causes the error on IPs from a specific region, but these are all rather unlikely things. If none of the above helped you to reproduce the problem, then you probably just did not find the correct request in all the data generated by the custom_log_file-call / tcpflow. Try to increase your chances by getting a more accurate timestamp. You can use microtime() in php as a replacement for date(). Check your webserver, if you can get something more accurate than seconds in your error log. Write your own implementation of "tail", that gives you a more accurate timestamp,... Reduce the load on the system, so that you don't have to choose from that much data (try another time of day, load of users to different servers,...)
circle the problem once you can reproduce
Now once you can reproduce it should be a walk in the park to find the actual cause. You can find the parameter that causes the error by trial and error or by comparing it to other requests that caused an error, too, looking for similarities. And then you can see what this parameter does, which libraries access it, etc. You can disable every component one by one that uses the parameter until you can't reproduce anymore. Then you got your component and can dive into the problem deeper.
Tell us what you found. I am curious ;-).
I had such an error, too. Found out that I returned a sql object in my session class (that was used by the session_handler) instead of returning nothing or at least not the sql object. First look into your _write and _read methods, if you too return some incorrect stuff.
Notice: ... Unknown on line 0 - How to find correct line, it's NOT "line 0"
I realize this question has already been answered, but I'll add this since it may help someone:
I managed to (unintentionally) produce errors without a stack frame from a function which used its own error handler to maintain control of execution while calling a potentially "dangerous" function, like this:
// Assume the function my_error_handler() has been defined to convert any
// PHP Errors, Warnings, or Notices into Exceptions.
function foo() {
// maintain control if danger() crashes outright:
set_error_handler('my_error_handler');
try {
// Do some stuff.
$r = danger();
} catch (Exception $e) {
$r = 'Bad Stuff, Man!';
}
restore error_handler();
return $r;
}
The "untraceable failure" would happen at the end of the program execution if the logic in "Do some stuff" returned from foo() directly, bypassing the call to restore_error_handler(). What I took away from the experience is this:
PHP maintains a stack of error handlers which gets deeper/taller with each call to set_error_handler().
Bad Stuff can happen if you push error handlers onto the stack and don't clean up after yourself before the program exits "normally".
This was a tough bug to isolate - I basically narrowed the problem down to the above function and then stared at it until my eyes bled.
So how would I have tracked this down, knowing what I know now? Since I don't know of any way to inspect the PHP error handler "stack" directly, I'm thinking it might make sense to use a Singleton object to encapsulate all set/restore operations for PHP error handlers. At least then it would be possible to inspect the state of the Singleton before exiting the program normally, and if "dangling" error handlers are detected to generate a sensible failure/warning message before PHP freaks out.
Instead of wrapping code in a try/catch block, what happens when you register an exception handler? Clearly your try/catch block is not catching the exception, thus resulting in the errors logged to Apache. By registering a handler, you can be sure any uncaught exception is handled.
Also, if you're using namespaces in your application, make sure you write \Exception in your catch block (or include the Exception class via a use statement).
This may be a little late but one issue I discovered when moving a site from a local to a remote server. I was using Concrete5 cms had developed my site locally(windows 8 in xampp) and then uploaded to a remote server running Cent 0S
Windows mysql by default is case insensitive and created a lower case database. Once this was uploaded to the remote server I received the "Exception thrown without a stack frame in Unknown on line 0?"
I then corrected the database tables case and my site started working again.
For us, this error was due to inadvertently serializing SimpleXML objects.
If you are using SimpleXML objects with 5.3.3, make sure you are are casting the node values to whatever you need (e.g. string) if you are serializing the values in the session.
Before:
$token = $response->Token->Value;
/* token saved in session, results in line 0 error */
After:
$token = (string) $response->Token->Value;
/* token saved in session, no error */
I had completely the same error. A very spacial case: if you connect an unnamed function (closure) hook to an object instance's hook point. After that you try to serialize this object.
I had the same error after filling the Illuminate Eloquent model's Fillable property incorrectly. Note the last 3 elements of the array, one is missing a coma.
protected $fillable = [
'budget',
'routestatus' ,
'userroutenumber'
'totalmovingseconds',
'totalidleseconds'
];
I had the same error, it appeared upgrading server from centos 5 to centos 6 and downgrading PHP from 5.4 to 5.3. Actual issue was PHP apc, not configured properly. Check your APC. I was using Symfony2, so you might find some help at Symfony Unable to allocate memory for pool
one simple way to produce this error is an old server with register_globals = On. then you only need two lines of code:
<?php
$_SESSION["my_var"] = "string";
$my_var = new MyClass(); //could be any class, i guess
?>
as soon as you reload this page once, you'll get the Exception thrown without a stack frame in Unknown on line 0 - error. seems like there is a conflict between the instance of the class and the (session) variable.
at least this is how i got this annoying error which is so hard to debug.
This problem occurred for me when I changed the namespace on a few Symfony bundles. Deleting the files in the the symfony cache directory fixed the issue.
Likely you have a corrupt/inconsistent table in the database. Try dumping the database. If you get a error that's the time. Repair that table and the issue should go away.
It is for this reason why clean install works. The clean install is just that clean.
mysqlcheck should work but if it does not show and issue still do above.

Count number of file requests triggered

Is it possible with PHP(5) or other Linux tools on an apache debian webserver to get the file requests a single http request made?
for performance reasons i would like to compare them with the cached "version" of my cake app.
non-cached that might be over 100 in some views.
cached only up to 10 (hopefully).
afaik there are 3 main file functions:
file_get_contents(), file() and the manual fopen() etc
but i cannot override them so i cannot place a logRequest() function in them.
is there any other way? attaching callbacks to functions? intercepting the file requests?
This suggestion does not seems intuitive, but you can take look on xdebug - function trace
Once you have xdebug installed and enabled, you can using all sort of configuration to save the profiling into a disk file and you can retrieve it later. Such as profiling results for different URL save into different disk file.
To monitoring file system related functions, you can do a parse of the text file(profiling results) and do a count of matchable functions (programmable or manually)
The way I would do it would be to create a custom function that wraps around the one you need.
function custom_file_get_contents($filename) {
$GLOBALS['file_get_contents_count']++;
return file_get_contents($filename);
}
And just replace all of your calls to file_get_contents with custom_file_get_contents. This is just a rudimentary example, but you get the idea.
Side note, if you want to count how many files your script has included (or required), see get_included_files()
You can use Xdebug to log all function calls
Those so-called "function traces" can be a help for when you are new to an application or when you are trying to figure out what exactly is going on when your application is running. The function traces can optionally also show the values of variables passed to the functions and methods, and also return values. In the default traces those two elements are not available.
http://www.xdebug.org/docs/execution_trace
Interesting question. I'd start with the stream_wrapper ... try to replace them with custom classes.
There is a pecl extention called ADB (Advanced PHP Debugger) that has tow functions that would be very useful for a cse like this - override_function() and rename_function(). You could do something like this:
rename_function('file_get_contents', 'file_get_contents_orig');
function file_get_contents($filename) {
logRequest();
return file_get_contents_orig($filename);
}
It looks like ADB is pretty easy to install, too.
See http://www.php.net/manual/en/book.apd.php

Categories