The error I get is this:
Element USER is undefined in a Java object of type class [Ljava.lang.String;
The lines of code I get this error are when I do anything like this:
SESSION.user.functionName()
It's randomly and I assume is happening after the user's session is expired. My problem is first of all, isn't the SESSION scope always a structure? How/Why does ColdFusion think it's a string.
Regardless, my main problem is I am using CFWheels. All my controllers extend the main Controller.cfc of course and all my controllers (except the public one) filter through a checkLogin function. That function has this in it:
<cfif !structKeyExists(session, "user")>
<cfif !structKeyExists(params,'layout') || params.layout EQ true>
<cfset redirectTo(route="home",error="You must be logged in to continue.") />
<cfelse>
<cfset flashInsert(error="You session has expired and you must login to continue. <a href=''>Reload the Page</a> to login.") />
<cfset redirectTo(controller="Shared",action="ajaxError") />
</cfif>
</cfif>
In this part of the function, I explicitly check if user exists in the session and if it doesn't one way or the other I'm sending them somewhere else. How on earth does the code get past this part to then fail when the session is somehow a string?
Not to mention there are various other places before I get to the error line where I'm making sure various things in the SESSION.user object are correct.
What was happening was on ajax requests. Some ajax requests load reports and such that can take several seconds to query, especially before some caching takes place. If a user executes an ajax call and then logs out, technically the request could make it through all my permission checking to get to the controller (it takes just milliseconds) but in the controller while fetching data from the models the user is logged out.
Then by the time the view is ready to load, the Session is cleared. If I use anything from the session scope there, it errors out.
I think I'll fix this by adding a filter that runs after the controller action to check if the session scope is still there. If it's not I'll just abort the request. I don't have model logic in any of my views, but I sometimes reference methods in the SESSION.user scope. Probably not purist MVC.
On the cases where the logout happens before parts of the controller are complete, I'll just let those errors happen as they may and ignore them, knowing the user really isn't seeing it happen.
Related
I'm having trouble validating a nonce created with wp_create_nonce() inside a hidden input with the name nonce in an html form:
<input type="hidden" name="nonce" value="<?php echo wp_create_nonce('action_name'); ?>" />
The form submission is done via ajax and validated with check_ajax_referer('action_name','nonce'). This always returns -1. All REST endpoints have been tested without nonces and work 100% fine.
The issue seems to stem from wp's user identifcation.
My debugging so far
Nonce creation
Within wp-includes/pluggable.php wp_create_nonce('action_name') creates a nonce hashing various variables including the user id and the action.
Ajax call
I submit an ajax call which calls check_ajax_referer('action_name','nonce'). This in turn calls wp_verify_nonce($nonce,$action) which verifies the nonce by hashing the same variables and comparing the two.
Reverse engineering to locate problem
My problem is that wp_create_nonce('action_name') is being created with the correct user id. However, when I run check_ajax_referer('action_name','nonce') which calls wp_verify_nonce($nonce,$action) which in turn calls wp_get_current_user(); no user is found (user id is 0).
Evidence the problem is to do with user id
If I temporarily edit wp-includes/pluggable.php to force my user id, the nonce validation works fine. It's as if ajax requests to a known and valid endpoint are being treated as if the user is logged out regardless of whether they are or not.
I'm clearly missing something here, but I have no idea what.
This is happening because a separate nonce with the action wp_rest is not being sent by the server to the client and received back from the client in an HTTP request header called X-WP-Nonce with every REST request.
To get this working, you will have to generate a nonce like this:
wp_create_nonce('wp_rest')
...and provide it to the client making the rest call. Once your client has the nonce value, you need to add it to every REST request e.g.:
headers: {
'X-WP-Nonce': nonce,
}
Creating the nonce on the server and accessing it on the client can be done several ways. Using wp_localize_script() is the most common and probably best practice for WordPress. wp_localize_script() addds a global variable to the client for a script to access. See https://developer.wordpress.org/reference/functions/wp_localize_script/.
I know a lot of people have had issues with Ajax and older versions of Coldfusion, but I'm using Coldfusion 11 Developer on my local machine and am finding it impossible to bind - under all circumstances - using Coldfusion functions, to a CFC, although it's not always the same error that gets returned.
I can't use autosuggest for a cfdiv when that binds to a CFC - but I can bind to autosuggest data on the same page, including from a database. When I bind to a CFC, invariably, the error message in CFDebug comes up as
"error:widget: Bind failed for autosuggest lastname, bind value is not a 1D array of strings.
info:http: CFC invocation response: ["Barken","Barnes"] ...
... by which you can see, that the bind IS a 1D array of strings and the CFC produced them, but wouldn't return them to the calling page!
I've also tried making the CFC much simpler, removing the database element and manually creating a straightforward 1D array of strings, but the same error comes up as when fed from my database.
So I made a test even simpler, avoiding databases and arrays to test ordinary, simple binding, not involving autosuggest - just an ordinary bind to a CFC (I always can successfully bind to data on the same page, or a URL.)
Here's the simplest test code, which still doesn't work:
<body>
<cfform id="myForm" name="myForm">
Enter your name into the box:<br />
<cfinput type="text" name="myText">
</cfform>
<hr />
Below is a cfdiv container, with a bind to a CFC:<br />
<cfdiv bind="cfc:bindsource.getDivContent({myText})"></cfdiv>
</body>
This is the CFC, named bindsource.cfc, in the same folder as the form page:
<cfcomponent output="false">
<cffunction name="getDivContent" returntype="string" access="remote" >
<cfargument name="edit">
<cfreturn "Your entered content was: #arguments.edit#">
</cffunction>
</cfcomponent>
In this case, the error I get is:
window:global: Uncaught exception: TypeError: Cannot convert '_289[i]' to object (http://localhost:8500/CFIDE/scripts/ajax/package/cfajax.js, line 872)
info:http: CFC invocation response: "Your entered content was: William"
(William is the text I entered into the box on the main page. line 872 in the cfajax.js is "872 throw new SyntaxError("parseJSON")"
In this simple test, on my main page, both before and after I enter something into the text input, in the area of what would be the cfdiv, the word "undefined" appears.
Sometimes, if I don't get the 1D array of strings error on some of the test pages, I get this can't convert to object error.
All the examples I've tried - not just my own stuff but all the samples I can find - run, up to the point where the Ajax error kicks in, so there are no other syntax errors. In all cases, the form page loads and runs, the CFC seems to get called, processes as appropriate - CFDebug shows me correct output of the CFC in the debug window - but then nothing ever comes back to the calling page. If I use a url bind, or a same page bind, it does - with a CFC, it doesn't. Ever.
When I test the CFC independently in a direct URL with method and argument passed, it works - I get the same result as the CFC invocation response.
Has anybody EVER got a CFC bind to work in Coldfusion? What am I missing or is CF11 just flawed? The whole things seems a bit unstable. I also get "cannot find CFC" errors, but if I do nothing, switch off, start up again - that particular error doesn't happen again for the same files until sometime later in the session, after repeated attempts to get one of the tests to work.
Wow - that was an obscure one, but I now know what's causing it.
Thanks for the suggestions, especially the one from #Dan Bracuk mentioning conflicts with javascript in the Application.cfc file, which led me to it, but it also helped to know the basic code should and did actually work, as others suggested, so the issue obviously had to do with something else.
Firstly, I removed my Application.cfc file completely - and for the first time, I could bind to a cfc. So then it was a question of finding what, in the Application.cfc, might be doing it.
Well, as it's my development set up, I'm dumping some variables to the page in the onRequestEnd function of Application.cfc. By removing them - it works. Put any of them back (dumps of server, cgi, session, application variables etc.) and again the cfc bind will not work.
I'm not using onRequestEnd for anything other than the variable dumps, but I thought to test what might happen if I were, still while removing the variable dumps. So I just added a simple cfinclude in the onRequestEnd function (the included cfm file does nothing at all - it's an empty cfm framework page with doctype and empty head/body tags that do or output nothing) and again, the cfc bind does not work.
It seems like it (onRequestEnd) will accept basic operations like cfset a=2+1 directly in onRequestEnd (but not in an included file) and the cfc will bind, but that's all (obviously not done exhaustive testing on what you can still do - basically, onRequestEnd is pretty unusable if you want to bind to your CFC.)
So that's it, the onRequestEnd function basically can't be relied upon if the bind to a CFC is to work. If you want it just to perform maths or maybe other things - perhaps you can get away with using it.
Hope this helps somebody else. It's been driving me nuts for weeks.
For what it's worth, so people can compare to their own setup and in case it doesn't apply in every development circumstance, I've been using the CF11 Developer Edition and I'm using the built-in Tomcat server on port 8500.
Thanks again everyone.
I was wondering if the following can be done in codeigniter.
Let's assume I have a file, called Post.php, used to manage posts in an admin interface.
It has several methods, such as index (lists all posts), add, update, delete...
Now, I access the add method, so that the url becomes
/posts/add
And I add some data. I click "save" to add the new post. It calls the same method with an if statement like "if "this->input->post('addnew')"" is passed, call the model, add it to the database
Here follows the problem:
If everything worked fine, it goes to the index with the list of all posts, and displays a confirmation
BUT
No the url would still be posts/add, since I called the function like $this->index() after verifying data was added. I cannot redirect it to "posts/" since in that case no confirmation message would be shown!
So my question is: can i call a method from anther one in the same class, and have the url set to that method (/posts/index instead of /posts/add)?
It's kinda confusing, but i hope i gave you enough info to spot the problem
Cheers!
Use the redirect() in conjunction with CodeIgniter's Flash Data, or opt for AJAX.
I'm new to wheels and still learning. It seems to me that every post of a form needs to call an action that maps to a method in the particular model. However, is it possible for a form to post to itself?
What I want to avoid is people navigating to an action view directly - which seems to throw an error. I'd also like to do a lot of self-posting because it might mean I won't have to have a lot of empty files laying around in my views folder.
Another advantage I was thinking about was the fact that if a form is self posting, I'd have the benefit of having it used globally. For example, I might have a form in my header that I want my user to fill out anywhere in the website. Or is there a way to detect where the user came from and do a dynamic redirectTo?
Many thanks,
Michael.
To avoid errors due to users browsing to post actions, look at Verification:
http://cfwheels.org/docs/chapter/verification
So your create and update actions would be configured like this in the controller's init:
<cffunction name="init">
<cfset verifies(only="create,update", post=true, params="comment", paramsTypes="struct")>
</cffunction>
It is not unreasonable to redirect the user back to the previous page after the form has posted. Look at redirectTo(back=true) for your success action.
http://cfwheels.org/docs/1-1/function/redirectto
<cffunction name="init">
<cfscript>
verifies(only="create,update", params="comment", paramsTypes="struct");
provides("html,json");
</cfscript>
</cffunction>
<cffunction name="create">
<cfscript>
comment = model("comment").new(params.comment);
comment.save();
if (isAjax())
{
renderWith(comment);
}
else
{
if (comment.hasErrors())
redirectTo(back=true, error="There was an error saving the comment.");
else
redirectTo(back=true, success="The comment was posted successfully.");
}
</cfscript>
</cffunction>
Yes, I like Craig's answer that AJAX is a good solution, but you also need to consider what happens if the AJAX fails and the form is ultimately posted to the URL through a non-AJAX request. Best to provide a fully accessible experience.
Michael, you may want to consider making a form like that Ajaxy. In other words, you can have it submit the form data, using jQuery or similar, to a remote CFC method (i.e., a method whose access attribute is set to "remote"). That CFC could work its magic per usual and return the appropriate response that you act on in your view.
Here is a link to the Wheels docs "Wheels, Ajax and You". There's some nice stuff in that section and it might be what you're looking for here!
What little I know about Wheels is that it's an opinionated MVC framework inspired by Ruby on Rails. You are requesting help on avoiding the the Model-View-Controller pattern by having the form post to itself and bypass the controller. This should not be possible or at least discouraged in such a framework.
A good MVC framework should allow you to reuse your model, views and in some cases even controllers - globally.
When a user requests a page, is this when a session is started for that user? From what I can tell, a session is started as soon as you make a page request...
If this is the case, when do you create session variables? i.e. username, password, preferences, etc... just any time?
Yes the session scope for the user is setup on the first request. However it depends on your preference as to when you want to set various flags and values. You probably don't want to put password in the session scope though.
What I like to do is put user specific values in a user struct. So on request start I'd check for the variable and setup if it doesn't exist. For example...
<cfif not structkeyexists(session, "user")>
<cfset session.user = {
authorized = false
, admin = false
, username = ''
, accountid = ''
<!--- etc --->
} />
</cfif>
When the user logs in you can then fill in the appropriate values and set session.user.authorized = true
When the user logs out the nice thing about this approach is you can just delete the users struct.
<cfset structdelete(session, "user") />
Then on the next page the check will be made again for the user struct and created if it doesn't exist.
The basics of configuring and using session variables are explained here.
A session is basically a logical relationship between a client and an application, so session variables are available from the client's first request to your application, and the session is typically persisted across requests using cookies which uniquely identify the session, although this can be also done by passing the identifiers in the url. It's worth paying attention to your session timeout settings, for example you may want to provide a shorter timeout to bots/crawlers which don't set cookies and will therefore initiate a new session for each page request (more details on this).