Trigger an URL with a cron job - cron

I'm working on a Symfony 3 website and I need to call a URL of my website with a cron job.
My website is hosted on OVH where I can configure my cron job.
For now, I have setup the command : ./demo/Becowo/batch/emailNewUser.php
emailNewUser.php content :
<?php
header("Location: https://demo.becowo.com/email/newusers");
?>
In the log I have :
[2017-03-07 08:08:04] ## OVH ## END - 2017-03-07 08:08:04.448008 exitcode: 0
[2017-03-07 09:08:03] ## OVH ## START - 2017-03-07 09:08:03.988105 executing: /usr/local/php5.6/bin/php /homez.2332/coworkinwq/./demo/Becowo/batch/emailNewUser.php
But emails are not sent.
How should I configure my cron job to execute this URL ?
Or should I call directly my controller ? How ?

ok, finally it works !!!
Here are the step I followed for others :
1/ You need a controller to send emails :
As the controller will be called via command, you need to injec some services
em : entity manager to flush data
mailer : to access swiftMailer service to send the email
templating : to access TWIG service to use template in the email body
MemberController.php
<?php
namespace Becowo\MemberBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Becowo\CoreBundle\Form\Type\ContactType;
use Becowo\CoreBundle\Entity\Contact;
use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
class MemberController extends Controller
{
private $em = null;
private $mailer = null;
private $templating = null;
private $appMember = null;
public function __construct(EntityManager $em, $mailer, EngineInterface $templating, $appMember)
{
$this->em = $em;
$this->mailer = $mailer;
$this->templating = $templating;
$this->appMember = $appMember;
}
public function sendEmailToNewUsersAction()
{
// To call this method, use the command declared in Becowo\CronBundle\Command\EmailNewUserCommand
// php bin/console app:send-email-new-users
$members = $this->appMember->getMembersHasNotReceivedMailNewUser();
$nbMembers = 0;
$nbEmails = 0;
$listEmails = "";
foreach ($members as $member) {
$nbMembers++;
if($member->getEmail() !== null)
{
$message = \Swift_Message::newInstance()
->setSubject("Hello")
->setFrom(array('toto#xxx.com' => 'Contact Becowo'))
->setTo($member->getEmail())
->setContentType("text/html")
->setBody(
$this->templating->render(
'CommonViews/Mail/NewMember.html.twig',
array('member' => $member)
))
;
$this->mailer->send($message);
$nbEmails++;
$listEmails = $listEmails . "\n" . $member->getEmail() ;
$member->setHasReceivedEmailNewUser(true);
$this->em->persist($member);
}
}
$this->em->flush();
$result = " Nombre de nouveaux membres : " . $nbMembers . "\n Nombre d'emails envoyes : " . $nbEmails . "\n Liste des emails : " . $listEmails ;
return $result;
}
}
2/ Call you controller as a service
app/config/services.yml
app.member.sendEmailNewUsers :
class: Becowo\MemberBundle\Controller\MemberController
arguments: ['#doctrine.orm.entity_manager', '#mailer', '#templating', '#app.member']
3/ Create a console command to call your controller
Doc : http://symfony.com/doc/current/console.html
YourBundle/Command/EmailNewUserCommand.php
<?php
namespace Becowo\CronBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
class EmailNewUserCommand extends ContainerAwareCommand
{
protected function configure()
{
// the name of the command (the part after "php bin/console")
$this->setName('app:send-email-new-users')
->setDescription('Send welcome emails to new users')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
// outputs a message to the console followed by a "\n"
$output->writeln('Debut de la commande d\'envoi d\'emails');
// access the container using getContainer()
$memberService = $this->getContainer()->get('app.member.sendEmailNewUsers');
$results = $memberService->sendEmailToNewUsersAction();
$output->writeln($results);
}
}
4/ Test your command !
In the console, call you command : php bin/console app:send-email-new-users
5/ Create a script to run the command
Doc (french) : http://www.christophe-meneses.fr/article/deployer-son-projet-symfony-sur-un-hebergement-perso-ovh
..Web/Batch/EmailNewUsers.sh
#!/bin/bash
today=$(date +"%Y-%m-%d-%H")
/usr/local/php5.6/bin/php /homez.1111/coworkinwq/./demo/toto/bin/console app:send-email-new-users --env=demo > /homez.1111/coworkinwq/./demo/toto/var/logs/Cron/emailNewUsers-$today.txt
Here it took me some time to get the correct script.
Take care of php5.6 : it has to match your PHP version on OVH
Don't forget to upload bin/console file on the server
homez.xxxx/name has to match with your config (I found mine on OVH, and then in the logs)
IMPORTANT : when you upload the file on the server, add execute right (CHMOD 704)
6/ Create the cron job in OVH
Call your script with the command : ./demo/Becowo/web/Batch/EmailNewUsers.sh
Language : other
7/ Wait !
You need to wait for the next run. Then have a look on OVH cron logs, or on your own logs created via the command in the .sh file
It took me several days to get it..
Enjoy !!

As commented above, you should do it with a symfony commaad. This is an example for you.
NOTE: Although it is working, you can always improve this example. Especially the way command calls your endpoint.
Controller service definition:
services:
yow_application.controller.default:
class: yow\ApplicationBundle\Controller\DefaultController
Controller itself
namespace yow\ApplicationBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\Response;
/**
* #Route("", service="yow_application.controller.default")
*/
class DefaultController
{
/**
* #Method({"GET"})
* #Route("/plain", name="plain_response")
*
* #return Response
*/
public function plainResponseAction()
{
return new Response('This is a plain response!');
}
}
Command service definition
services:
yow_application.command.email_users:
class: yow\ApplicationBundle\Command\EmailUsersCommand
arguments:
- '#http_kernel'
tags:
- { name: console.command }
Command itself
namespace yow\ApplicationBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class EmailUsersCommand extends Command
{
private $httpKernel;
public function __construct(HttpKernelInterface $httpKernel)
{
parent::__construct();
$this->httpKernel = $httpKernel;
}
protected function configure()
{
$this->setName('email:users')->setDescription('Emails users');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$request = new Request();
$attributes = [
'_controller' => 'yow_application.controller.default:plainResponseAction',
'request' => $request
];
$subRequest = $request->duplicate([], null, $attributes);
$response = $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
$output->writeln($response);
}
}
Test
$ php bin/console email:users
Cache-Control: no-cache, private
X-Debug-Token: 99d025
X-Debug-Token-Link: /_profiler/99d025
This is a plain response!
1.0
200
OK

Related

How to store a reference to parent object in perl6 (conversion from perl5)

I'm trying to create a Perl 6 client interface to an RPC server, with the class hierarchy matching the server URLs. e.g.
# for url path: /account/login
# client code:
$client.account.login;
For this to work, the 'child' object (account) needs to store a reference to its parent object (client).
This is what I've tried:
#!/usr/bin/env perl6
use v6;
class MyApp::Client::Account {
has $!client;
method login() {
# fake login
$!client.session_id = 'abc';
return 'ok';
}
}
class MyApp::Client {
has $.session_id is rw;
method account() {
state $empire = MyApp::Client::Account.new( :client(self) );
return $empire;
}
}
use Test;
plan( 2 );
my $client = MyApp::Client.new;
my $response = $client.account.login;
is( $response, 'ok', 'login successful' );
ok( $client.session_id, 'client has session_id' );
Running this gives the following error message:
1..2
Method 'session_id' not found for invocant of class 'Any'
in method login at test.pl6 line 9
in block <unit> at test.pl6 line 29
# Looks like you planned 2 tests, but ran 0
I don't really know any perl6 class/object idioms yet - am I even going about the design in the right way?
If so, why is $!client within the login() method undefined?
For reference, here's the perl5 (bare-bones) version that I'm trying to convert from:
#!/usr/bin/env perl
package MyApp::Client::Account;
sub new {
my $class = shift;
return bless {#_}, $class;
}
sub login {
my $self = shift;
# fake login
$self->{client}->session_id( 'abc' );
return 'ok';
}
package MyApp::Client;
sub new {
my $class = shift;
return bless {#_}, $class;
}
sub session_id {
my $self = shift;
if (#_) {
$self->{session_id} = shift;
}
return $self->{session_id};
}
sub account {
my $self = shift;
$self->{account} ||= MyApp::Client::Account->new( client => $self );
return $self->{account};
}
package main;
use Test::More tests => 2;
my $client = MyApp::Client->new;
my $response = $client->account->login;
is( $response, 'ok', 'login successful' );
ok( $client->session_id, 'client has session_id' );
Which gives the expected output:
1..2
ok 1 - login successful
ok 2 - client has session_id
So there are a few ways that Perl 6 OO differs from other implementations I've used. One is the awesome way that it will auto-fill your member variables for you. However, this only works when they are defined with public accessors.
class G {
has $!g;
has $.e;
method emit { say (defined $!g) ?? "$!g G thing" !! "nada G thing" }
}
Which will lead to the following behavior:
> my $g = G.new( :g('unit-of-some-kind'), :e('electric') )
G.new(e => "electric")
> $g.emit
nada G thing
> $g.e
electric
So when you are passing self as a reference to MyApp::Client::Account, it isn't being bound to the $!client variable because the default constructor will only bind to publicly accessible member variables.
You can either choose to make it accessible, or you can take the object construction logic into your own hands. This is how I imagine the code to look were I to need my own version in Perl 6 but had to keep client private:
class MyApp::Client::Account {
has $!client;
method new(:$client) {
self.bless( :$client );
}
# binds $!client to $client automatically based on the signature
submethod BUILD(:$!client) { }
method login() {
# fake login
$!client.session_id = 'abc';
return 'ok';
}
}
class MyApp::Client {
has $.session_id is rw;
has $.account;
# the default .new will call .bless for us, which will run this BUILD
submethod BUILD {
$!account = MyApp::Client::Account.new( :client(self) );
}
}
It can take some getting used to the new versus BUILD distinction. One key distinguishing point is that self is not available in the scope of new, but it is available in the scope of BUILD (albeit in a not-yet-fully-constructed form).

How to fix if operation is not defined in the WSDL using php nusoap

I am currently working on a project that uses web service PHP Nusoap. I implement it at first in the local computer and it is already working perfectly fine, it can insert already in the database.Since, we are also deploying our project in the production server (Linux RHEL 4) so we also need to include the web service. In implementing this in the production server, we got this error :
Operation '' is not defined in the WSDL for this service Here is the
full details :
<?xml version="1.0" encoding="utf-8"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode xsi:type="xsd:string">SOAP-ENV:Client</faultcode>
<faultactor xsi:type="xsd:string"></faultactor>
<faultstring xsi:type="xsd:string">Operation &apos;&apos; is not defined in the WSDL for this service
</faultstring>
<detail xsi:type="xsd:string"></detail>
</SOAP-ENV:Fault>
HERE IS THE CODE :
client.php
<?php
require_once('lib/nusoap.php');
$data = json_decode(file_get_contents("php://input"), true);
$file_name = $data['file_name'];
$location = $data['location'];
$client = new nusoap_client('http://servername:port/WebService/server.php?wsdl', true);
if ($SERVER['REQUEST_METHOD'] == 'POST') {
$err = $client->getError();
if ($err) {
echo "<h2> Constructor error </h2><pre>" . $err. "</pre>" ;
echo "<h2> Debug </h2><pre>" . htmlspecialchars($client->getdebug(), ENT_QUOTES) . "</pre>" ;
exit();
}
$datas = array (
'file_name' => $file_name,
'location' => $location
);
$result = $client->call('InsertData', $datas);
if ($client->fault) {
echo "<h2> Fault (Expect - The request contains an invalid SOAP Body)</h2> <pre>" ;
print_r ($result);
echo "</pre>";
} else {
$err = $client->getError ();
if ($err) {
echo "<h2> Error </h2><pre>" . $err. "</pre>";
} else {
print_r ($result);
}
}
} else if ($_SERVER['REQUEST_METHOD'] != 'POST') {
echo "Method is not POST " ;
}
?>
server.php
<?php
require_once('lib.nusoap');
$server = new soap_server();
$server->configureWSDL('Database Sample Insertion', 'urn:Insert');
$server->soap_defenconding = 'UTF-8' ;
$server->register('InsertData',
array (
'file_name' => 'xsd:file_name',
'location' => 'xsd:location'
),
array ('return' => 'xsd:string'),
'urn:Insert',
'urn:Insertwsdl#InsertDate',
'rpc',
'literal'
);
function InsertData ($file_name, $location) {
$db_host = 'localhost';
$db_username = 'username';
$db_password = '' ;
$db_name = 'sample' ;
$conn = new mysqli ($db_host, $db_username, $db_password, $db_name);
if ($conn->connect_error) {
trigger_error('Database connection failed : ' .$conn->connect_error , E_USER_ERROR);
}
$sql = "INSERT INTO transaction (`filename`, `location`) VALUES ('$file_name', '$location')";
$query = $conn->query($sql);
}
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '' ;
$server->service($HTTP_RAW_POST_DATA);
?>
what does this problem means and how can we solve this? Or how to setup the web service PHP Nusoap in the production server? Any ideas/suggestions is appreciated. Thanks
I'v had the same problem when PHP/Apache version changed at my server. Im my case the problem was located inside nusoap library function: parse_http_headers()
There is a function used to get all HTTP headers getallheaders() and it seems not getting all headers as it should. There were no Content-Type which is required for nusoap to parse request (ex. text/xml).
Fortunately nusoap checks if function getallheaders() exists and if not it uses $_SERVER array to parse headers.
Finally the one thing I had to do was to change one line of code inside nusoap.php file to disable this function:
if (function_exists('getallheaders')){ ...
to this one:
if (0 && function_exists('getallheaders')){ ...
Hope this help others!

How to get baseUrl in Yii2 advanced app after Url rewrite

I have used Yii2 advanced application. i rewrite url in frontend and backend.
After rewrite Frontend url is
localhost:83/Working-copy/mySite/
And For Backend
localhost:83/Working-copy/mySite/admin
Now i want to get base url like
/Working-copy/mySite/
But i don't get it properly
I have tried following ways,
echo Yii::getAlias('#web') // ans= /Working-copy/mySite/admin
echo Yii::getAlias('#backend') // ans= /var/www/Working-copy/mySite/backend
echo Yii::getAlias('#webroot') // ans= /var/www/Working-copy/mySite/backend
echo Yii::$app->request->BaseUrl // ans= /Working-copy/mySite/admin
echo Yii::$app->getBasePath(false) // ans= /var/www/Working-copy/mySite/backend
echo Yii::$app->homeUrl // ans = /Working-copy/mySite/admin/
In some url i get /var/www/ and in some url get /admin/.
i only want my project name.
any solution please?
Create components into common folder.
Add Request.php
namespace common\components;
class Request extends \yii\web\Request {
public $web;
public $adminUrl;
public function getBaseUrl(){
return str_replace($this->web, "", parent::getBaseUrl()) . $this->adminUrl;
}
public function getActualBaseUrl(){
return str_replace($this->web, "", parent::getBaseUrl());
}
public function resolvePathInfo(){
if($this->getUrl() === $this->adminUrl){
return "";
}else{
return parent::resolvePathInfo();
}
}
}
Use Yii::$app->request->getActualBaseUrl().

Detect locale and alter url (redirect) to include locale

What i want to do is, to detect the language of a users browser and redirect him to a page containing the locale in url.
I thought, the easiest way would be, to register a kernel listener. So that is what i did:
services:
kernel__request_listener:
class: Me\MainBundle\Listener\KernelRequestListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
calls:
- [ setContainer, [ #service_container ] ]
KernelRequestListener.php
...
/**
* #Service
*/
class KernelRequestListener
{
/**
* #Observe("kernel.request")
*/
public function onKernelRequest( GetResponseEvent $response )
{
if( $newLocale = $this->newLocale() )
{
$parmArray = $request->get('_route_params');
$parmArray['_locale'] = $newLocale;
$redirectResponse = new RedirectResponse( $this->getContainer()->get('router')->generate($request->get('_route'), $parmArray) );
$redirectResponse->headers->setCookie( new Cookie('b_locale', $newLocale, time() + 2592000) );
$response->setResponse( $redirectResponse );
}
}
...
}
The method $this->newLocale() just detects if the user should be redirected to another language and returns the new language code (i.e. DE or FR).
Here comes the problem:
I am using assetics to compress the js files and jms/i18n-routing-bundle to do the locale-based routing. When the kernel listener switches locale, the page starts loading the js files over and over again. also, there are several pages (i.e. the profiler, login/logout etc.) where no redirect should take place as it makes no sense or breaks smthing.
Is a kernel listener the right place to do such a redirection or is there any better place. How to resolve the problems above?
Add, before your code:
public function onKernelRequest(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$request = $event->getRequest();
if ($request->getRequestFormat() !== 'html') {
return;
}
[CODE]

Search Facebook using PHP SDK

In the last days, I'm working on the application which needs to search for users on Facebook. Since the FQL query for "username" was deprecated/canceled, I have decided to use common search API.
I use PHP so FB PHP SDK is the way I'd prefer. I have used it earlier for FQL queries, just like this:
// $api is already initialized, with access_key, app secret and so on
$users = $api(array(
'method' => 'fql.query',
'query' => "SELECT first_name,last_name FROM user WHERE uid='12345'",
));
I'd like to build the search query in the similar way. Especially, I don't want to urlencode the parameters, specify access key, app secret and all the stuff the SDK is supposed to do for me. However, I haven't been able to build this query using SDK yet. Is there any possibility to do it? If yes, how? I have found long list of sdk-supported "api calls" but I need to build the query for graph.facebook.com/search?arguments.
Thanks in advance.
EDIT: To make it clear, I don't want to build the string by myself. I know this solution works. But imho it's ugly when I have SDK:
$name = urlencode(trim($first_name . " " . $last_name_));
$users = $this->facebook->api("/search?q=$name&type=user&access_token=$key");
Searching User via Graph API using php-sdk 3.1.1
User will need to authorize your app before making a search for
users.
{
"error": {
"message": "A user access token is required to request this resource.",
"type": "OAuthException"
}
}
Php-skd 3.1.1 init.
<?php
require './src/facebook.php';
$facebook = new Facebook(array(
'appId' => 'your-app-id',
'secret' => 'your-app-secret',
));
$user = $facebook->getUser();
if ($user) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
error_log($e);
$user = null;
}
}
/* */
if ($user) {
$logoutUrl = $facebook->getLogoutUrl();
} else {
$loginUrl = $facebook->getLoginUrl();
}
?>
Search includes, encoding search term, setting results limit, and
offset for paging.
<?php
/* Get Search parameter from url or post and urlencode it. */
$q = urlencode($_GET['qs']);
if(!$_GET['qs']){
$q = urlencode($_POST['qs']);
if(!$_POST['qs']){
/* Default Search Term */
$q = "Shawn+E+Carter";
}
}
/* Get Results Limit from url or set default. */
$limit = $_GET['limit'];
if (!$_GET['limit']){
$limit = 60;
}
/* Get Offset from url or set default for paging. */
$offset = $_GET['offset'];
if (!$_GET['offset']){
$offset = 0;
}
/* Make Graph API call to user */
$usersearch = 'search%3Fq='.$q.'%26type=user%26limit='.$limit.'%26offset='.$offset.'';
echo '<pre style="text-align: left;">';
print_r($usersearch);
echo '</pre>';
?>

Resources