I've got some files using raw php (including config files) that's used for the automatic mailing stuff in my server.
Suppose inside this file I define a couple of constants (define(...)) and an array filled with database connection info, like user, host and so).
The website is done using Yii, so it also uses a config file.
These raw files can be placed anywhere (inside protected, outside, at the same level of index.php, whatever).
Now the problem comes that I've got a different configuration file (and different users/password for databases, and so) outside Yii, but I need to use it in some places inside Yii, too.
Is there a clear way to import these files to a controller? I've done it placing them inside extensions, but the raw functions didn't work from there.
The best approach would be to see if you can put your custom code into class files and put those in the components directory or similar and convert your files to classes (if they aren't already). That way you can get at your data without a lot of mixing of code which is going to be hard to maintain.
Simple approach will be to place the files in extensions and add the path of the extensions to your yii configuration. Then make a controller and call methods from its actions. Lets consider an example of swiftmailer. Here is a custom controller you can use.
class mailerController extends Controller{
public function actions()
{
return array(
//can add other actions here
);
}
public function actionIndex(){
echo "use mailer?e=<email>&m=<message>&sub=<subject> to send mail from the site to the email address";
}
public static function actionSendMail($e,$m,$sub){
$content = $m ; // can use a template and then assign to content
$SM = new SwiftMailer(); //the external method, should be present in include path
// Get config
$mailHost = Yii::app()->params['mailhost'];
$mailPort = 25; // Optional
$Transport = $SM->smtpTransport($mailHost, $mailPort);
$Mailer = $SM->mailer($Transport);
$Message = $SM
->newMessage($sub)
->setFrom(Yii::app()->params['sitemail'])
->setTo($e)
->addPart($content, 'text/html');
return ( $Mailer->send($Message));
} }
once your controller is ready, it can be called like
yoursite.com/mailer?e=<email>&m=<message>&sub=<subject>
Related
I am trying to include a file for the ExactTarget api inside a controller. Basically, an ajax request submits a form to a route /send. In the controller for that route I have a class, but it fails when it makes a call to the ExactTarget library.
class sendexacttarget{
public function send($f3)
{
$client = new ExactTargetSoapClient($wsdl, array('trace'=>1));
}
}
I don't want to load the ExactTarget file in the index.php, because then it will load on every request. Ideally, I'd like to just load it here, in the send function. I've tried require() and include() but neither work.
I'm trying to include one file exacttarget.php and that file has a require statement calling soap-wsse.php which has another require statement calling xmlseclibs.php.
So first question: Is it possible to load these files from the controller and if so how?
The second part of the question is this. I am able to combine all of the PHP from those three files into one file and include from the index.php, but I have not been successful calling them as separate files. I have tried this:
$f3->set('AUTOLOAD','App/Controllers/;vendor/exacttarget/xmlseclibs.php;vendor/exacttarget/soap-wsse.php;vendor/exacttarget/exacttarget.php');
But it doesn't work.
I also tried this from another SO thread:
$f3->set('AUTOLOAD','App/Controllers/;vendor/exacttarget/');
$params = require 'vendor/exacttarget/exacttarget.php';
Doesn't work. This last bit of code I thought worked for a bit, but then it stopped working. I'm wondering if there is some caching going on?
In any case, if anyone can please help me include this library, even if on all pages I'd be very grateful. Also, this library I'm using is not available via composer so I don't think using composers autoload is an option.
Thanks.
The framework autoloader expects the following conditions in order to be working:
one class per file
each file named like the class it contains and located in a directory structure representating its namespace
See the documentation and this SO question for more details.
Since the external library you're trying to load doesn't meet those requirements, I suggest you three solutions:
1) require all the dependencies inside your controller:
public function send($f3) {
require('vendor/exacttarget/xmlseclibs.php');
require('vendor/exacttarget/soap-wsse.php.php');
require('vendor/exacttarget/exacttarget.php');
$client = new ExactTargetSoapClient($wsdl, array('trace'=>1));
}
2) create a service that will require all the dependencies and return an ExactTargetSoapClient instance:
// index.php
f3->SOAP = function($wsdl,array $options=[]) {
require_once('vendor/exacttarget/xmlseclibs.php');
require_once('vendor/exacttarget/soap-wsse.php.php');
require_once('vendor/exacttarget/exacttarget.php');
return new ExactTargetSoapClient($wsdl,$options+['trace'=>1]);
}
// controller
public function send($f3) {
$client = $f3->SOAP($wsdl);
}
NB: if the $wsdl and $options arguments are the same all other your app, you can even remove the function arguments and have a simple $f3->SOAP().
3) concatenate the three files into one single file properly named and have it autoloaded:
// vendor/exacttargetsoapclient.php
<?php
class ExactTargetSoapClient extends SoapClient {
// etc.
class WSSESoap {
// etc.
/**
* xmlseclibs.php
* etc.
Now set up the autoloader:
// index.php
$f3->AUTOLOAD = 'App/Controllers/;vendor/';
And you're done:
// controller
public function send($f3) {
$client = new ExactTargetSoapClient($wsdl, array('trace'=>1));
}
The AUTOLOAD autoloader doesn't support file names. It looks like you are using Composer so please use its autoloader:
require_once 'vendor/autoload.php'
Please adjust the vendor path relative (or use an absolute path) to the file which is requiring the autoload.php file.
I want to create a common functionality in Moodle. That function will be accessible to all the pages like login, course etc. So, in which file or lib, I need to write the function and how will I access it? My function name will be like:
function addpoints() {
return $data;
}
I'd recommend creating a local plugin to hold functions like that. You will then need to call:
require_once($CFG->direct.'/local/mylocalplugin/lib.php');
addpoints();
If you are using moodle 2.6 or above, you can make use of the automatic class loading feature ( http://docs.moodle.org/dev/Automatic_class_loading ) to load your code without the require_once line, but that is a bit more fiddly to set up.
I am having a controller IndexController.php in which action is something like this
class IndexController extends CustomControllerAction {
public function preDispatch() {
if (!$this->view->authenticated) {
$this->_redirect('/users/login');
}
}
public function indexemailAction() {
//somecode which calculates certain things
}
}
NOw,I need to call the action "indexmailAction" inside the IndexController.php with an independent php file
The php file is indextest.php
<?php
//Need to write some code to call indexmailAction in IndexController.php
?>
What should I write in this file ......
Thanks in advance
I know this is a few years old, and this may not be the intended use of the classes/functions, but I've found the following quite useful in isolated files that are called from the command line.
The problem this solves for me is that it eliminates spawning of Apache processes. The solution is great because I can access the some Controller/Action needed that I would from the URL.
In almost any ZF1 based app, you can copy your index file and keep everything the same and just comment out the following line.
$application->run();
Anything below this line you can access with your autoloaders etc. It's crude, but it works. Unfortunately, you'll soon find yourself with limited access to a lot of the files your application has, and the feeling the only way you can access the files needed is through a Controller/Action.
Instead, I use the following in a new file below $application->bootstrap() ( still removing the $application->run() ):
$front = Zend_Controller_Front::getInstance();
// You can put more here if you use non-default modules
$front->setControllerDirectory(array(
'default' => APPLICATION_PATH.'/controllers'
));
$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer();
$viewRenderer->setNeverRender(true);
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
$req = new Zend_Controller_Request_Http("http://anydomain.tld/controller/action");
// Example just to see how this can be extended
$req->setParam("someVar", "someValue");
$front->setRequest($req);
$front->dispatch();
In the end you have a isolated PHP file that bootstraps everything the same as your main index.php for the web, but you can manually trigger a controller/action as needed, giving you easier access to the rest of the files with how ZF1 intended you to access them.
Controllers are designed to be used in an MVC, not by scripts. Your controller should assemble request variables, direct them to models and return an HTTP response of some sort. Your scripts should act directly on the models instead.
Anyhow, if you insist, you can instantiate a controller class and call methods just like any other class as long as you inject any dependencies that the MVC would have.
If you want logic used in multiple places in your actions, then it should go in an action helper or if very generic code, then in a custom library (/library/custom/)
NB: The authentication would be better suited in a plugin rather than the pre-dispatch method in every controller.
You should not have to call a controller action for this, your logic should reside in your models. Then you can create a new instance of your model and invoke the appropriate methods. example :
require_once '/path/to/mymodel.php';
$mymodel = new Mymodel();
$data = $mymodele->fetchAll();
PS: Maybe you should think of creating a restful api to handle calls from outside your application
UPDATE:
ok, I see now what you need, The best way to achieve it is to call a url instead of a file (e.g. website.com/emails/send), if you are worried about security you can use some preshared key to make sure the request comes from you, send it with the request and check if it's correct in your action.
What solutions,patterns usually used for this?
I want to get rid of if/else statements in my controllers, models and so on.
For example:
if($domain==1) {
// do this
}
elseif($domain==2) {
// do this
}
elseif...
Want to get rid of this madness. Can't imagine what mess will be, when there will be at least 20 websites.
Currently i'm using config and routing files for each domain. But that's not enough.
Can't get rid of this mess inside models and controllers.
I was thinking about some kind of placeholders and separate static class for each domain with method for those placeholders + magic calls.
For example i have action inside controller:
public function postAction(){
$model=new Model();
$this->view->data=$model->get($placeholder_generates_and_return_settings_array); // else default is used
// custom placeholder
// execute custom class method if it's exist
// some model again
// custom placeholder
// execute custom class method if it's exist
// etc
}
Current view is provided inside placeholders Class, types can be assigned. Like data modification, config generation for model etc.
How would you resolve this issue with multiple domains, without cloning controllers, models or creating innumerous if/elseif statements for each domain inside them?
UPDATE
How to describe what i need. I'm trying to create reusable controllers with default logic in it. Just filling/MIXING controller with domain related logic in required places(placeholders), data modification etc. Something like controller-template possible, any patterns exist?
Providing placeholder with all required(CURRENT) data for it's modification if required or further processing AND returning it back.
Guess i'll have to create my own "bicycle". :D
Based on the information you provide I assume that you wish to display your data differently based on the domain. Also assuming that your data remains unchanged you could use a strategy pattern to solve your problem.
Your class structure would then look as follows:
class yourClass
{
protected $_strategy;
public function setStrategy($strategy)
{
$this->_strategy = $strategy;
}
public function showYourData()
{
return $this->_strategy->show($this)
}
}
For each domain you build a separate strategyclass as follows:
class domainStrategy
{
public function show(yourClass $yourClass)
{
// Get your classdata here
$data = $yourClass->whateverFunctionYouNeed();
// Do what you want for this domain
return $output;
}
}
I hope this gets you started, I'm sure you can find more documentation for the strategypattern when you need it
I suggest to create a dispatcher that loads information based on domain criteria.
Something like:
dispatch.php
<?php
...
$domain = get_domain_function(); // here you may automate the domain retrieval
include ('controllers/' . $domain . '.php')
...
?>
controllers/domain1.php ... controllers/domainn.php
<?php
...
do the domain specific business logic here
...
?>
Have a folder for each domain.
When the user accesses the web site (maybe the contactus.php page), this page will check if there is a corrisponding contactus.php file in the domain folder. If there is, it will include that file, otherwise, it will do it's default behaviour.
Want to get rid of this madness. Can't imagine what mess will be, when there will be at least 20 websites.
Why on earth would you put 20 websites in 1 project???
Just use separate vhosts if you are on apache.
http://httpd.apache.org/docs/2.0/vhosts/examples.html
Other webservices also have this functionality (although they might have a different name).
If you want to prevent you need to copy common/shared functionality in you projects.
Just setup some form of a library and with the common functionality which you use in your different projects.
If you look into the MVC pattern http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller you could even have some default views in your library for the projects to use (if needed these can be overridden of course).
if($domain==1) {
// do this
}
elseif($domain==2) {
// do this
}
elseif...
I'm curious what "do this" for important thing is that you need do to it for all sites. It's not possible to specifically answer the question without knowing that.
I can assume you would like to set some variables, for example set up a session, perhaps create some other (database) object with different parameters, or set some variables in a template.
You could do that using some kind of controller, but again, it depends on what you want to achieve.
class Controller
{
public abstract function DoAction1();
// Group shared functionality, call it with different parameters
public function ShowHomePage($view)
{
$template->assign('view', $view);
}
}
class Domain1Controller extends Controller
{
public function DoAction1()
{
// do this
}
}
class Domain2Controller extends Controller
{
public function DoAction1()
{
// do this
}
}
And in your calling code (the router) you simply call Controller->ShowHomePage($view) or Controller->DoAction1() or whatever, but only after you determined on what domain you are and what controller you want to address.
I often switch between .NET and PHP development. With ASP.NET sites I save configuration information (e.g. connection strings, directories, application setting) in the web.config file which is appropriately protected and easy to access the values, etc.
In PHP, I solve this with a class that has static methods for each variable:
class webconfig {
public static function defaultPageIdCode() {
return 'welcome';
}
}
The file is included by the app variables are accessed with a one-line:
$dp = webconfig::defaultPageIdCode();
And since PHP isn't compiled, it is easy to telnet in and change a value for a website anyway, so this solution works fairly well and gives me these two advantages:
I can add logic to a config variable without breaking its interface with the application
these config variables appear as intellisense in my e.g. Eclipse, NetBeans, etc.
But I can imagine there are other ways people solve saving web config settings in PHP which may have other advantages.
Especially those who have experience with a number of PHP frameworks, what are other ways of saving config variables and their advantages and disadvantages?
I've decided to list all known methods along with their advantages and disadvantages.
I've marked this answer as a community wiki so collaboration is easier.
Global Constants
Assigning:
define('CONFIG_DIRECTIVE', 'value');
Accessing:
$object = new MyObject(CONFIG_DIRECTIVE);
Advantages:
Has global scope.
Autocompleted by most IDEs.
Has an agreed upon naming convention (UPPERCASE_UNDERSCORE_SEPARATED).
Disadvantages:
Directives cannot contain arrays (prior to v7.0.0).
Special Notes:
Cannot be reassigned.
Alternate Syntax Files
For example: XML, INI, YAML, etc.
Assigning:
Simply edit the file in it's specific language. (For example, for INI files: config_directive = value.)
Accessing:
The config file needs to be parsed. (For example, for INI's: parse_ini_file().)
Advantages:
Most likely has a syntax more suited for a config file.
Disadvantages:
Possible overhead of accessing and parsing the file.
Array
Assigning:
$config['directive'] = 'value';
Accessing:
The cleanest method of accessing configuration values using this method is to pass the required values to the object that needs them on creation, or pass them to your container object and let it handle passing them out internally.
$object = new MyObject($config['directive']);
$container = new MyContainer($config);
Advantages:
Directives can be arrays.
Disadvantages:
No autocompletion.
Special Notes:
Variable collisions can occur. If this is a concern, name your array appropriately to avoid them.
Class
Assigning:
There are many different class based implementations.
Static class.
myCfgObj::setDirective('DIRECTIVE', 'value');
Instanced class.
myCfgObj->setDirective('DIRECTIVE', 'value');
Accessing:
Again there are various class based implementations.
Static class.
$object = new MyObject(myCfgObj::getDirective('DIRECTIVE'));
Instanced class.
$object = new MyObject(myCfgObj->getDirective('DIRECTIVE'));
Advantages:
Can be autoloaded.
Disadvantages:
Tends to be a bit verbose.
Can be hard to maintain if a container class is not being used.
I tend to use a Settings static class in PHP, this is because
It has a global scope.
You can enable/disable changes to protected configs.
You can add any settings during anywhere within runtime.
You can make the class automated to fetch public configs from a file/database.
Example:
abstract class Settings
{
static private $protected = array(); // For DB / passwords etc
static private $public = array(); // For all public strings such as meta stuff for site
public static function getProtected($key)
{
return isset(self::$protected[$key]) ? self::$protected[$key] : false;
}
public static function getPublic($key)
{
return isset(self::$public[$key]) ? self::$public[$key] : false;
}
public static function setProtected($key,$value)
{
self::$protected[$key] = $value;
}
public static function setPublic($key,$value)
{
self::$public[$key] = $value;
}
public function __get($key)
{//$this->key // returns public->key
return isset(self::$public[$key]) ? self::$public[$key] : false;
}
public function __isset($key)
{
return isset(self::$public[$key]);
}
}
Then within your runtime, if you loaded this file first, followed by your database config file, your database config file would look like so:
<?php
Settings::setProtected('db_hostname', 'localhost');
Settings::setProtected('db_username', 'root');
Settings::setProtected('db_password', '');
Settings::setProtected('db_database', 'root');
Settings::setProtected('db_charset', 'UTF-8');
//...
echo Settings::getProtected('db_hostname'); // localhost
//...
Settings::setPublic('config_site_title', 'MySiteTitle');
Settings::setPublic('config_site_charset', 'UTF-8');
Settings::setPublic('config_site_root', 'http://localhost/dev/');
As you can see the we have a method __get that should only be allowed to grab public variables, An example of why we have this is as follows:
$template = new Template();
$template->assign('settings', new Settings());
Regardless the fact that we have used this object as a static object, the values should still stand so within the template you can now do, lets say.
<html>
<head>
<?php echo isset($settings->config_site_title) ? $settings->config_site_title : 'Fallback Title'; ?>
</head>
</html>
And this will only allow you to have access to the public data during the initialized period.
This can get a lot more complex but more system friendly, some examples:
A loadConfig method to automatically parse a config file, xml, php, yaml.
If you register an shutdown_function you can auto update the database with new settings.
You can auto-populate the class with config from that database.
You can implement iterators to make it compatible with looping.
Lots more.
This too me is by far the best methods to complete this job.
The way I do it is directly store them in an array and save the file as config.php
<?php
$config['dbname'] = "mydatabase";
$config['WebsiteName'] = "Fundoo Site";
$config['credits'] = true;
$config['version'] = "4.0.4";
?>
Thi is the way most PHP frameworks like Wordpress, etc do it.
In PHP I always use a ".htaccess" to protect my config file (Double protection)
Note: "Best way" never exists. Every application and framework doing it their own style. While your example is doing the trick i think it's a little bit resource-heavy for a simple config file.
You can do it with single variables like Amber pointed out
You can do it with arrays this is the most common approach and you can always easily edit your config file.
You can do it with .ini files that PHP easily parsing
Edit:
Edward please take a look at parse_ini_file's examples. You can load the .ini file with a simple command then you can use the variables in a class like in your example.
There are pretty much possibilities I think, but the most common methods are storing as plain text in files like .csv, .ini, .xml. With little tricks you can protect these files, so that no one can load the files directly.
an INI-File example:
;<?php die(); ?>
[config1]
var1 = 'value1';
var2 = 'value2';
...
[config2]
...
The ; is considered a comment in ini files. So when you read in the file with an ini-parser, this line will be ignored. If someone accesses the file directly via url the die()-function will be executed. This works only, if the INI-file wears a file-extension like .php so that the server knows that this should be executed and not diplayed as plain text.
Possible disadvantage of most file-base-config-storages are problems with some utf8-characters.
Zend_Config is a component of the Zend-Framework, which provides possibilities for several storage-adapters with an easy to use api.
Since PHP is able to use OO, I like to go with a "Config class":
class Config
{
/**
* ---------------------------------
* Database - Access
* ---------------------------------
*/
/**
* #var String
*/
const DB_DRIVER = 'pgsql';
const DB_USER = 'postgres';
const DB_PASSWORD = 'postgres';
const DB_NAME = 'postgres';
}
It is easy accessable with Config::DB_DRIVER. No need to include the file since the application autoloader will do that for you. Of course, protecting the file still needs to be done.
Telnet? OMG I've fallen into a timewarp and arrived in 1992!
But seriously, IIRC there are tools which allow asp.net (and other languages) to parse session data - which is just a serialized php array. I'd have a go at implementing the global settings as a sort of shadow session within PHP. Even if you don't store your config settings as a serialized PHP array, you could map them into the session at runtime using your own session handler.
In terms of where you store the data - that's a more tricky one when you're presumably running on a Microsoft platform. Obviously you don't want the expense of disk access for every request. Although NT does some disk caching it's not (IME) quite as effective as other OS. Memcached appears to be one solution to this. It does appear to be usable from asp.net.
HTH
The usual route is to use define:
define('MYSQL_USER', 'ROOT');
and access it all over the application via MYSQL_USER :
$user = MYSQL_USER;
However arrays are not supported in this way.
There are few possibilities:
You can use config file (ini, json, xml or yaml). For ini you have parse_ini_file, for JSON there is json_decode (+file_get_contents), for YAML you have to use external library (search for sfYaml)
You can have a config file with variables or constants (better for immutable config and accessible in all scopes), which you includes in your script:
define('ROOT_DIR', '\home\www');
$sRootDir = '\home\www';
If you are OO-oriented, you can wrap it in class, as properties - you do not have getter method for every property, you can just have:
class Config
{
public $var1 = 'xxx';
public $var2 = 'yyy';
}
($c = new Config(); print $c->var1)
or
static class Config
{
public static $var1 = 'xxx';
public static $var2 = 'yyy';
}
(print c::$var1)
The best is to have registry-type class, implementing singleton pattern and capable to read config from given file.
In order to be testable, I use a Config class that holds the actual configuration data and an AppConfig static class that holds a reference to a Config object loaded at bootstrap from application wide configuration files (dependency injected at bootstrap). In the tests environment, I only change the Config object. See https://github.com/xprt64/Config