How to get cookies with guzzle? - guzzle

The Guzzle site is very weak documentation. I realized that I needed to look at the source code to use all the features of the library, but I still can not fully understand the source code.
How to get cookies with Guzzle from any website? What class to look at?

The cookies representation in guzzle is part of the PSR-7's ServerRequestInterface implementation, e.g of the ServerRequest class. In the class is defined an array property $cookieParams. To this variable you can either assign the $_COOKIE variable (through the call to the static method fromGlobals()) or an array of your choice (inclusive $_COOKIE) by calling withCookieParams(). To read the content of the $cookieParams array you just need to call getCookieParams().
Example using fromGlobals() - having the role of a ServerRequest factory:
<?php
use GuzzleHttp\Psr7\ServerRequest;
/**
* Create a ServerRequest instance, populated with superglobals:
* $_GET
* $_POST
* $_COOKIE
* $_FILES
* $_SERVER
*/
$serverRequest = ServerRequest::fromGlobals();
// Display the content of $_COOKIE.
var_dump($serverRequest->getCookieParams());
Example of directly creating a ServerRequest instance and assigning a cookies array to a copy of it - in order to maintain the immutability of the request object:
<?php
use GuzzleHttp\Psr7\ServerRequest;
// Directly create a ServerRequest instance.
$serverRequest = new ServerRequest('GET', 'http://localhost/mypath?var=somevar#myfragment', [], NULL, '1.1', $_SERVER);
// Create a clone instance with the specified cookies array.
$serverRequest = $serverRequest->withCookieParams($_COOKIE);
// Display the content of the cookies list.
var_dump($serverRequest->getCookieParams());
There is also another implementation, the one of GuzzleHttp\Cookie\CookieJarInterface, e.g the class GuzzleHttp\Cookie\CookieJar (see here) This is documented on http://docs.guzzlephp.org, at:
Quickstart Cookies
Request Options - Cookies
Handlers
In CookieJar class you can assign a $cookieArray in constructor and have some methods to handle its values (getCookieValue(), getCookieByName(), setCookie() etc).

Related

In Backpack, where is the appropriate place to put the authorize() call?

Backpack controllers do not contain Rest methods as is typical with Laravel, but use traits to implement CRUD operations, and occasionally (but not always - delete does not for example) setup methods (setupListOperation for example).
For authorization, for the rest of my app I use Gate declarations in AppServiceProvider, and declare $this->authorize() to check authorization in each of my controllers.
Where can I use authorize() to check each of the operations I implement from Backpack? I couldn't find a method that seemed appropriate to override in order to run that authorization before proceeding.
You will normally do this in your FormRequest classes, see https://backpackforlaravel.com/docs/4.1/crud-tutorial#the-request
Example:
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
use Illuminate\Foundation\Http\FormRequest;
class TagRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
}
Then you'd set the request as a validator for the given opperation:
Example
protected function setupCreateOperation()
{
$this->crud->setValidation(TagRequest::class);
// TODO: remove setFromDb() and manually define Fields
$this->crud->setFromDb();
}
NOTE: While its not clear in the documentation or generated controllers (if you use the command line generator) you can in fact set a setup method for ALL opperations:
If you look at the packages allin.com/vendor/backpack/crud/src/app/Http/Controllers/CrudController.php file, in the setupConfigurationForCurrentOperation method you'll find:
/**
* Load configurations for the current operation.
*
* Allow developers to insert default settings by creating a method
* that looks like setupOperationNameOperation (aka setupXxxOperation).
*/
protected function setupConfigurationForCurrentOperation()
{
$operationName = $this->crud->getCurrentOperation();
$setupClassName = 'setup'.Str::studly($operationName).'Operation';
//.....
/*
* THEN, run the corresponding setupXxxOperation if it exists.
*/
if (method_exists($this, $setupClassName)) {
$this->{$setupClassName}();
}
}
This means that if your controller defines a setupDeleteOperation function, it WILL be called during the setup of the delete route for your CRUD.
After making use of #Wesley Smith's answer, I discovered a one-step approach to this.
As Wesley mentions, you can create setup methods for all of the crud operations, and this works as an excellent place to pass an auth. However, it does not update the other operation's links. For example, list will still contain a link to "edit," even if it's unauthorized. You can remove these with individual lines, but there's an easier way.
Instead, you can use the Setup method to pass allow/deny methods. Here's what my setup() now appears as.
public function setup()
{
CRUD::setModel(Workshop::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/workshop');
CRUD::setEntityNameStrings('workshop', 'workshops');
if (Gate::denies('admin.workshop.list'))
$this->crud->denyAccess('list');
if (Gate::denies('admin.workshop.show'))
$this->crud->denyAccess('show');
if (Gate::denies('admin.workshop.create'))
$this->crud->denyAccess('create');
if (Gate::denies('admin.workshop.update'))
$this->crud->denyAccess('update');
if (Gate::denies('admin.workshop.delete'))
$this->crud->denyAccess('delete');
}
This will not only deny access to the methods, but update each method with the appropriate #can blade directives, meaning unauthorized methods won't appear as links.

Returning Array in USER_INT userFunc leads to <!--INT_SCRIPT output

I have a userFunc which I call via
lib.random = USER_INT
lib.random {
userFunc = My\Plugin\UserFunc\Functions->random
}
when I return a Array and try to access it is fails.
<v:variable.set name="random" value="{f:cObject(typoscriptObjectPath: 'lib.random')}" />
{random.max}
When I try to debug out it I get some <!--INT_SCRIPT string
Did anyone know the problem and a Solution?
/e:
I would like to make the problem a little clearer by describing the Szenario.
I have a Plugin with a Login form. When the User logs in I set a JWT with various basic informations (name, email).
This Informations have to be displayed on various places around the Website, not only on one page (for example profile page). Some cases are prefilled forms or just silly "Hello, Paul" stuff.
So when I first log in (Fresh browser, no cache) then I read "Hello, Paul" after I log out and log in with a another Account (Lets call it "Peter") then It still is written "Hello, Paul" , nor "Hello, Peter". When I clear my browser Cache then everything is fine.
Maybe this helps maybe to solve my dilemma. :)
TL;DR: uncached parts in TYPO3 are replaced in the generated page output string using markers and cannot communicate in the direction intended here. Selectively caching, disabling cache or detaching the data from the main request (with XHR or other) are the only possible methods.
It should be clear that USER_INT achieves its functionality by string replacement in the generated page body. This means, among other things, that:
You can never pass the output of a USER_INT to anything in Fluid, not even if the entire page is uncached. You will effectively be passing a string containing <!---INT_SCRIPT... (the entire marker).
You can however generate USER_INT from Fluid, which ends up in the generated page, which is then replaced with the rendered object (use f:cObject to render a USER_INT or COA_INT).
Then there are the use case context considerations. First of all, a cookie (in practice) changes the request parameters and should be part of the cache identifier that your page uses (it is not this way by default). Second, if said cookie changes the way the page renders (and it does, given your use case) this will cause trouble when the page is cached. Third, the page output changing based on a cookie indicates perhaps sensitive information or at the very least user-specific information.
Taking the above into account your use case should do one of the following things:
Either render the entire chunk of output that changes based on cookie, as USER_INT. That means wrapping the entire Fluid output and rendering it all without caching. Note that template compiling still happens (and you can use f:cache.static to hard-cache certain parts if they never change based on request parameters).
Or add the cookie value to the cHash (page hash value) so that having the cookie set means you request a specific cached version that matches the cookie. This is the preferred way if your cookie's values is generally the same for many users (e.g. it contains a selected contact person from a limited list and stores that in a cookie).
Or, in the case that your output contains actually sensitive information, require that the content element or page is only available when logged in with a specific group. This has two purposes: first, it protects the page from being viewed without authentication - but second, it also makes the page content not cache or be cached with the frontend user group ID as part of the cache identity.
Refactor to XHR request and make whichever endpoint it uses, a USER_INT or manually disabled cache context, then load the data. Or set the actual data in the cookie, then use JS to insert the values where needed.
Hopefully that clarifies the different contexts and why they can't communicate in the direction you're attempting; even if they had been exchanging strings instead of arrays.
See also: .cache sub-object in TypoScript which is where you would be able to craft a unique cache identifier for use case 2 described above.
USER_INT are not Cached, so the values for this are replaced after the cache is build up.
I think f:cObject is the wrong way. Implement an own ViewHelper to get the same data should be an better way.
<?php
namespace My\Plugin\ViewHelpers;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
class RandomViewHelper extends AbstractViewHelper
{
use CompileWithRenderStatic;
/**
* #var boolean
*/
protected $escapeOutput = false;
/**
* #param array $arguments
* #param \Closure $renderChildrenClosure
* #param RenderingContextInterface $renderingContext
* #return string
*/
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
return rand();
}
}
Now you can use it like following:
{my:random()} or <my:random />

CodeIgniter Form Validation callback to model from config rules?

My User_model have a public method called is_unique_email($email). This method checks if a user has a uniqe mail adress with some status flag checks. This is also the reason why I can't use the standard is_unique validation rule from CodeIgniter.
I'm using a form_validation.php with config array for my validation rule groups. My question is: How can I call the model method for checking the new user's e-mail address? I searched and tried so many things, but nothing work. My preferred call would be with | pipe separator.
Like: trim|required|max_length[70]|valid_email|<~ here comes the model callback ~>
Is there any solution for this callback or is there no way and I have to extend the Form_validation system library?
I'm using CodeIgniter 3.1.7.
Thanks in advance!
UPDATE:
Because I've always done things via extending the form_validation library I forgot about this:
https://codeigniter.com/user_guide/libraries/form_validation.html#callbacks-your-own-validation-methods
and this (anonymous functions):
https://codeigniter.com/user_guide/libraries/form_validation.html#callable-use-anything-as-a-rule
Might be better for you. When in doubt, always read the docs ;)
Yes you can extend the form_validation library. In application/library make a MY_Form_validation.php and have it extend CI's as such:
class MY_Form_validation extends CI_Form_validation {
then in it you can do something like this:
/**
* Checks to see if bot sum is valid
* e.g. equals the session stored values
*
* #param int $sum
* #return boolean
*/
public function valid_bot_sum($sum) {
$generated = $this->CI->session->bot_first_number + $this->CI->session->bot_second_number;
if ($generated !== intval($sum)) {
$this->set_message('valid_bot_sum', 'Invalid bot sum.');
return false;
} else {
return true;
}
}
and now your function can be accessed via pipe separators as any native form_validation validation function. Just be sure to set the message on false as I've done, otherwise you will get an error. You can access the CI instance like so $this->CI.
In your case you can either migrate the function from the model into this file, or you can call it by loading the model in the function and calling the function and just testing to see if it evaluates to true/false and handling as above.

Using save or put with Restangular results in "undefined" being included in URL

I am using Restangular to download an object, update it and then attempt to save back to the server using the save method. Here is the code that retrieves the object:
Restangular.one("survey", surveyID).getList().then (
function (response) {
$scope.survey = response[0];
}
);
This sets $scope.survey to a properly "restangularized" object, with the fields that come back from the GET request, along with the methods like save, put, etc.
If I then invoke the following function after making some edits to the $scope.survey object:
$scope.saveChanges = function () {
$scope.survey.save();
};
restangular tries to use the URL /survey/1/undefined for the PUT request (1 is the correct ID for the object).
My survey object doesn't have an id field (it's surveyID instead), and so I suspected this might be the problem. However, replacing the surveyID field with an id field changed the URL to be /survey/1/undefined/1
I have stripped down the object returned by the GET request to be just primitives, and this does not change the situation.
Why is the incorrect route being generated?
II discovered the problem was actually with the REST service; when called with GET /surveys/1, it was returning an array with a single object in it, rather than returning the object itself.
I think this caused restangular to think that a collection was being accessed (note that I was having to call getList rather than get in order to get a properly restangularized object).

How to Pass data/variables/objects to Zend_Controller_Plugin

I am converting an old ZF app (its using an early ZF version where we used to do manual app loading/config in the index.php) to latest version, and in one of the plugin we are sending data directly to the plugin constructor
$front->registerPlugin(new My_Plugin_ABC($obj1, $obj2))
Now in the current version we can register a plugin by directly providing the details in the application.ini and I want to stay with this approach(registering using config file). So while testing, I noticed the the plugin constructor is called fairly early in the bootstrapping, so the only option I am left with is using Zend_Registry to store the data, and retrieve it in the hooks. So is it the right way? or are there any other better ways
EDIT
The plugin was actually managing ACL and Auth, and its receiving custom ACL and AUTH objects. Its using the preDispatch hook.
Okay so you could consider you ACL and Auth handlers as a some application resources, and be able to add configuration options for them in you application.ini
//Create a Zend Application resource plugin for each of them
class My_Application_Resource_Acl extends Zend_Application_Resource_Abstract {
//notice the fact that a resource last's classname part is uppercase ONLY on the first letter (nobody nor ZF is perfect)
public function init(){
// initialize your ACL here
// you can get configs set in application.ini with $this->getOptions()
// make sure to return the resource, even if you store it in Zend_registry for a more convenient access
return $acl;
}
}
class My_Application_Resource_Auth extends Zend_Application_Resource_Abstract {
public function init(){
// same rules as for acl resource
return $auth;
}
}
// in your application.ini, register you custom resources path
pluginpaths.My_Application_Resource = "/path/to/My/Application/Resource/"
//and initialize them
resources.acl = //this is without options, but still needed to initialze
;resources.acl.myoption = myvalue // this is how you define resource options
resources.auth = // same as before
// remove you plugin's constructor and get the objects in it's logic instead
class My_Plugin_ABC extends Zend_Controller_Plugin_Abstract {
public function preDispatch (Zend_Controller_Request_Abstract $request){
//get the objects
$bootstrap = Zend_Controller_Front::getInstance()->getParam("bootstrap");
$acl = $bootstrap->getResource('acl');
$auth = $bootstrap->getResource('auth');
// or get them in Zend_Registry if you registered them in it
// do your stuff with these objects
}
}
Acl is needed so many other places hence storing it in Zend_Registry is cool thing to do and since Zend_Auth is singleton so you can access it $auth = Zend_Auth::getInstance() ; anywhere you like so no need for auth to be stored in registry .
Lastly if you have extended Zend_Acl class for your custom acl its better to make it also singleton . Then you can access acl My_Acl::getInstance(); where My_Acl is subclass of Zend_Acl .