Yii2 Allow action access only by POST request - php

I have created a yii2 controller, which meant to display statistics from database, for a specific user. There is a ajax request, performed to my controller action, but i want to restrict to allow only POST method for this action.
<?php
use yii\web\Response;
namespace app\controllers;
use Yii;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\web\Response;
use yii\filters\VerbFilter;
use app\models\StatsModel;
class DataController extends Controller
{
/**
* {#inheritdoc}
*/
public function behaviors()
{
return [
[
'class' => 'yii\filters\ContentNegotiator',
'only' => ['stats'],
'formats' => [
'application/json' => Response::FORMAT_JSON
],
],
];
}
/**
* {#inheritdoc}
*/
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
];
}
public function actionStats()
{
//how can i restrict this action to only POST http method?
return StatsModel::find()->all();
}
}
I need to restrict actionStats() to HTTP Post method only.

Usually you'd allow post only adding something like this to your behaviors:
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'stats' => ['POST'],
],
],
And if you are accessing this action only through ajax, in your action you could add the following check
if(Yii::$app->request->isAjax)
{
//in case you want to return JSON formatted response
Yii:$app->response->format = Response::FORMAT_JSON;
}
You can check this cookbook as well:
https://books.google.com.sv/books?id=CJrcDgAAQBAJ&pg=PA193&lpg=PA193&dq=yii2+isajax&source=bl&ots=lRFEiPbN3K&sig=MFGo7VostVkxNZDbXGemXrm-qA8&hl=es&sa=X&ved=0ahUKEwjE9ZXSh7nbAhWPk1kKHW3wCeEQ6AEIYTAF#v=onepage&q=yii2%20isajax&f=false
Finally, you can just make the check for post in your action like this
public function actionStats()
{
if(Yii::$app->request->isPost())
{
//your logic here
return StatsModel::find()->all();
}
else
//throw an exception or return false
}

Related

Yii2: Cannot process to get Session

I am using Yii2 Advanced version.
This is Login Model:
namespace common\models;
use Yii;
use yii\base\Model;
use common\models\User;
class LoginForm extends Model{
public $username;
public $password;
public $rememberMe = true;
public $verifyCode;
const BACKEND_TEST = 'none';
const BACKEND_ID = 'test';
const BACKEND_USERNAME = 'backend_username';
private $user;
public function rules(){
return [ [['username','password'],'required','message'=>'{attribute}required...'],
['username','validateUser'], ['verifyCode','captcha','captchaAction'=>'login/captcha','message'=>'Wrong'],
];
}
public function validateUser($attribute,$params){
$user = User::findOne(['username'=>$this->username]);
if(!$user || (md5($this->password) != $user['password'])){
$this->addError('password','Wrong>_<...');
}else{
$this->user = $user;
}
}
public function login(){
if(!$this->user){
return false;
}
var_dump($this->userInfo());
$this->createSession();
return true;
}
private function createSession(){
//Yii::$app->session->open();
Yii::$app->set(self::BACKEND_ID,$this->user['id']);
Yii::$app->set(self::BACKEND_USERNAME,$this->user['username']);
}
public function userInfo(){
return $this->user;
}
Also, there is LoginController that I think have no issue, and next thing is when user try to login and session will be opened, and direct to site page.
Here is the sitecontroller:
namespace backend\controllers;
use Yii;
use yii\web\Controller;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
use common\models\LoginForm;
/**
* Site controller
*/
class SiteController extends Controller
{
public function actionIndex()
{
//var_dump(Yii::$app->session->get(common\models\LoginForm::BACKEND_ID));
var_dump(LoginForm::userInfo());
return $this->renderPartial('index');
}
Every time I try to login and the Error message comes out and provides:
Invalid Configuration – yii\base\InvalidConfigException
Unexpected configuration type for the "test" component: integer
How to solve the issue, and I try to get $user that stores all the data and it seems to fail?
main.php:
<?php
$params = array_merge(
require(__DIR__ . '/../../common/config/params.php'),
require(__DIR__ . '/../../common/config/params-local.php'),
require(__DIR__ . '/params.php'),
require(__DIR__ . '/params-local.php')
);
return [
'id' => 'app-backend',
'basePath' => dirname(__DIR__),
'controllerNamespace' => 'backend\controllers',
'bootstrap' => ['log'],
'modules' => ['smister' => [
'class' => 'backend\modules\smister\smister',
],],
'components' => [
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => true,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'errorHandler' => [
'errorAction' => 'site/error',
],
/*
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
],
],
*/
],
'params' => $params,
];
You are using
Yii::$app->set(self::BACKEND_ID,$this->user['id']);
probably for set a param value ..
but the Class yii\web\Application (alias Yii::$app->set ) contain a function named set() that register component ..(so your error : Unexpected configuration type for the "test" component: integer) in this way your code is misundestood by Yii2 because your costant BACKEND_ID = 'test'; is not a component id but the key for a param
see this reference for check
http://www.yiiframework.com/doc-2.0/yii-web-application.html
http://www.yiiframework.com/doc-2.0/yii-di-servicelocator.html#set()-detail
for you scope if you need param you can use the file param.php
returning the param you need
file config/param.php
<?php
return [
'test' => 'my_initial_value',
];
and you can access this param simply using
\Yii::$app->params['test'],
or you can simply setting runtime
\Yii::$app->params['test'] = 'Your_value';

Calling unknown method: yii2mod\cms\controllers\CmsController::setInstance()

I don't understand why this error occur.
get error on call a cms
http://localhost/yii-cms/web/cms
Calling unknown method: yii2mod\cms\controllers\CmsController::setInstance()
i am try to use of yii2-cms
cmsController
<?php
namespace yii2mod\cms\controllers;
use Yii;
use yii2mod\cms\models\CmsModel;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii2mod\cms\models\search\CmsModelSearch;
use yii2mod\editable\EditableAction;
use yii2mod\toggle\actions\ToggleAction;
/**
* Class CmsController
* #package yii2mod\cms\controllers
*/
class CmsController extends Controller
{
/**
* #var string view path
*/
public $viewPath = '#vendor/yii2mod/yii2-cms/views/cms/';
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'index' => ['get'],
'create' => ['get', 'post'],
'update' => ['get', 'post'],
'delete' => ['post']
],
]
];
}
/**
* #inheritdoc
*/
public function actions()
{
return [
'edit-page' => [
'class' => EditableAction::className(),
'modelClass' => CmsModel::className(),
'forceCreate' => false
],
'toggle' => [
'class' => ToggleAction::className(),
'modelClass' => CmsModel::className(),
]
];
}
/**
* Lists all CmsModel models.
* #return mixed
*/
public function actionIndex()
{
$searchModel = new CmsModelSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render($this->viewPath . 'index', [
'dataProvider' => $dataProvider,
'searchModel' => $searchModel
]);
}
/**
* Creates a new CmsModel model.
* If creation is successful, the browser will be redirected to the 'view' page.
* #return mixed
*/
public function actionCreate()
{
$model = new CmsModel();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
Yii::$app->session->setFlash('success', Yii::t('yii2mod.cms', 'Page has been created.'));
return $this->redirect(['index']);
}
return $this->render($this->viewPath . 'create', [
'model' => $model,
]);
}
/**
* Updates an existing CmsModel model.
* If update is successful, the browser will be redirected to the 'view' page.
*
* #param integer $id
*
* #return mixed
*/
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
Yii::$app->session->setFlash('success', Yii::t('yii2mod.cms', 'Page has been updated.'));
return $this->redirect(['index']);
}
return $this->render($this->viewPath . 'update', [
'model' => $model,
]);
}
/**
* Deletes an existing CmsModel model.
* If deletion is successful, the browser will be redirected to the 'index' page.
*
* #param integer $id
*
* #return mixed
*/
public function actionDelete($id)
{
$this->findModel($id)->delete();
Yii::$app->session->setFlash('success', Yii::t('yii2mod.cms', 'Page has been deleted.'));
return $this->redirect(['index']);
}
/**
* Finds the CmsModel model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
*
* #param integer $id
*
* #return CmsModel the loaded model
* #throws NotFoundHttpException if the model cannot be found
*/
protected function findModel($id)
{
if (($model = CmsModel::findOne($id)) !== null) {
return $model;
} else {
throw new NotFoundHttpException(Yii::t('yii2mod.cms', 'The requested page does not exist.'));
}
}
}
i have following yii2-cms and it's work great
set instance error occur due to they can not find out given class and that's possible due to miss configuration.
follow Configuration Link https://github.com/yii2mod/yii2-cms#configuration
1) To use this extension first you need to configure the comments extension, after that you have to configure the main config in your application:
'modules' => [
'admin' => [
'controllerMap' => [
'cms' => 'yii2mod\cms\controllers\CmsController'
// You can set your template files
// 'layout' => '#app/modules/backend/views/layouts/main',
// 'viewPath' => '#app/modules/backend/views/cms/',
],
],
],
You can then access to management section through the following URL:
http://localhost/path/to/index.php?r=admin/cms/index
2) Add new Rule class to the urlManager array in your application configuration by the following code:
'components' => [
'urlManager' => [
'rules' => [
['class' => 'yii2mod\cms\components\PageUrlRule'],
]
],
],
3) Add to SiteController (or configure via $route param in urlManager):
/**
* #return array
*/
public function actions()
{
return [
'page' => [
'class' => 'yii2mod\cms\actions\PageAction',
// You can set your template files
'view' => '#app/views/site/page'
],
];
}
And now you can create your own pages via the admin panel, and access them via the url of each page.
Yes error is solved by following proper Configuration STEP.
Error is occur due to miss configure second step
2) Add new Rule class to the urlManager array in your application configuration by the following code:
'components' => [
'urlManager' => [
'rules' => [
['class' => 'yii2mod\cms\components\PageUrlRule'],
]
],
],
Full Configuration you need to did :
1) To use this extension first you need to configure the comments extension, after that you have to configure the main config in your application:
'modules' => [
'admin' => [
'controllerMap' => [
'cms' => 'yii2mod\cms\controllers\CmsController'
// You can set your template files
// 'layout' => '#app/modules/backend/views/layouts/main',
// 'viewPath' => '#app/modules/backend/views/cms/',
],
],
],
You can then access to management section through the following URL:
http://localhost/path/to/index.php?r=admin/cms/index
2) Add new Rule class to the urlManager array in your application configuration by the following code:
'components' => [
'urlManager' => [
'rules' => [
['class' => 'yii2mod\cms\components\PageUrlRule'],
]
],
],
3) Add to SiteController (or configure via $route param in urlManager):
/**
* #return array
*/
public function actions()
{
return [
'page' => [
'class' => 'yii2mod\cms\actions\PageAction',
// You can set your template files
'view' => '#app/views/site/page'
],
];
}
And now you can create your own pages via the admin panel, and access them via the url of each page.
You seem to be using the cms extension in your site component as-is.
In your web.php file, add this:
'components' => [
...
'i18n' => [
'translations' => [
'*' => [
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '#app/messages'
'sourceLanguage' => 'en',
],
],
],
]
...,
'controllerMap': => [
'cms' => 'yii2mod\cms\controllers\CmsController'
],
NOTE: You should exclude the path about configuring it as a component in the admin module since you're not using it anyway.
If you were using it in a module, then the steps documented in the README is just fine for you.

"NetworkError: 405 Method Not Allowed" in YII2 rest API

I am working on Yii2 rest API, When I call create action of enquiryontroller then I am getting this error : "NetworkError: 405 Method Not Allowed".
And also I go through YII2 documentation but not able to trace my issue.
Please check and revert, it will be a great help.
Here is controller code that is EnquiryController.php :
<?php
namespace frontend\controllers;
use Yii;
use common\models\Enquiry;
use yii\filters\ContentNegotiator;
use yii\web\Response;
use yii\filters\AccessControl;
use yii\rest\ActiveController;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\VerbFilter;
use yii\data\ActiveDataProvider;
class EnquiryController extends ActiveController
{
/**
* #inheritdoc
*/
public $modelClass = 'common\models\Enquiry';
public $serializer = [
'class' => 'yii\rest\Serializer',
'collectionEnvelope' => 'items',
];
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => HttpBearerAuth::className(),
];
$behaviors['contentNegotiator'] = [
'class' => ContentNegotiator::className(),
'formats' => [
'application/json' => Response::FORMAT_JSON,
],
];
return $behaviors;
}
public function actions()
{
$actions = parent::actions();
// disable the "delete" and "create" actions
unset($actions['create']);
unset($actions['delete'], $actions['view']);
unset($actions['index']);
// customize the data provider preparation with the "prepareDataProvider()" method
return $actions;
}
public function actionCreate()
{
$model = new Enquiry();
return Yii::$app->getRequest()->getBodyParams();
if ($model->load(Yii::$app->getRequest()->getBodyParams(), '') && $model->validate()) {
$model->slug = \common\components\Helper::slugify($model->title);
$model->user_id = Yii::$app->user->id;
$model->save();
//mail functionality
return true;
}
return $model;
}
}
and code in config/main-local.php :
'urlManager' => [
'class' => 'yii\web\UrlManager',
'baseUrl' => $baseUrl,
'enablePrettyUrl' => true,
'showScriptName' => false,
//'enableStrictParsing' => true,
'rules' => [
['class' => 'yii\rest\UrlRule', 'controller' =>['api'], 'pluralize'=>true],
],
],
],
'as access' => [
'class' => 'mdm\admin\components\AccessControl',
'allowActions' => [
'site/*',
'api/login',
'profile/*',
'api/activate-user',
'api/contact',
'home/*',
'post/*',
'pages/*',
'categories/*',
'guestbook/*',
'faq/*',
'news/*',
'events/*',
'enquiry/*',
'partners/*',
'api/signup'// add or remove allowed actions to this list
]
],
Have a look to this guide
// disable the "delete" and "create" actions
unset($actions['delete'], $actions['create']);
because in your code you disable the create, delete, view and index action
public function actions()
{
$actions = parent::actions();
// disable the "delete" and "create" actions ?????
unset($actions['create']); ////????
unset($actions['delete'], $actions['view']); /// ????
unset($actions['index']); ////????
// customize the data provider preparation with the "prepareDataProvider()" method
return $actions;
}

Passing values to multiple views

I've this code for the controller (I'm using the basic template for testing purposes:
use Yii;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\filters\VerbFilter;
use app\models\LoginForm;
use app\models\ContactForm;
class SiteController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout'],
'rules' => [
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['#'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
];
}
public function actionIndex()
{
$param = $this->somefunction();
return $this->render('index', [
"param" => $param
]);
}
public function actionLogin()
{
if (!\Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
return $this->goBack();
} else {
return $this->render('login', [
'model' => $model,
]);
}
}
public function actionLogout()
{
Yii::$app->user->logout();
return $this->goHome();
}
public function actionContact()
{
$param = $this->somefunction();
$model = new ContactForm();
if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
Yii::$app->session->setFlash('contactFormSubmitted');
return $this->refresh();
} else {
return $this->render('contact', [
'model' => $model,
"param" => $param
]);
}
}
public function actionAbout()
{
$param = $this->somefunction();
return $this->render('about', [
"param" => $param
]);
}
}
As you can notice, I'm passing param to multiple views with the same content so I want some time-saving way to send it only one time to all views.
Is that possible?
Currently, I'm using the session to store values and call the session in required views. I want something more convenience
You can use Controller and View events to achieve that.
Add this to your controller:
use yii\web\View;
...
public function beforeAction($action)
{
if (!parent::beforeAction($action)) {
return false;
}
$this->view->on(View::EVENT_BEFORE_RENDER, function() {
$this->view->params['param'] = ...;
});
return true;
}
If you want it in multiple controllers, either create another controller (extending from yii\web\Controller) for that and override beforeAction and then extend your controllers from custom one, or set it during application boostrap using BoostrapInterface.
Additionally you can add some condition:
if (in_array($action, ['create', 'update']) {
...
}
and custom param will be only passed in these actions.
in your controller you can redefine the init () function thanks to which you can assign to a variable of the controller the value you're interested

Yii2 Restfull APi RBAC Guest login

I have a rest full API in Yii2. I have the user model, controller and created a new rest action called login.
How can I set the action login to be executed by the guest users?
class UserController extends \yii\rest\ActiveController{
public function actions() {
$actions = parent::actions();
$actions['login'] = [
'class' => 'app\modules\user\actions\user\LoginUserAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
];
return $actions;
}
public function checkAccess($action, $model = null, $params = array()) {
return true;
}
}
You can set the access control rules on the behaviors function of your controller, instead of on the checkAccess property on the action:
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['access'] = [
'class' => AccessControl::className(),
'except' => ['login'],
'rules' => [
[
'allow' => true,
'actions' => ['foo', 'foo2'],
'roles' => ['admin'],
]
],
];
return $behaviors;
}
In this example, the access control is applied to all actions except 'login'. I left the rules part so you can have an example of how you make customized rules.

Categories