nodejs cannot find module 'zombie' with PHP mink - php

I'm trying out Mink (PHP) on Ubuntu 14.04; I basically did the following:
$ apt-show-versions nodejs
nodejs:amd64/trusty 0.10.45-1nodesource1~trusty1 uptodate
$ npm -v
2.15.1
$ sudo npm install -g zombie
npm WARN engine zombie#4.2.1: wanted: {"node":"^4.0.0"} (current: {"node":"0.10.45","npm":"2.15.1"})
...
zombie#4.2.1 /usr/lib/node_modules/zombie
├── ms#0.7.1
├── debug#2.2.0
...
$ ls /usr/lib/node_modules/zombie/node_modules/
babel-runtime bluebird debug eventsource iconv-lite jsdom lodash mime ms request tough-cookie ws
So, basically, even if I get a warning, the modules build, and should be in the directory /usr/lib/node_modules.
Then I do:
mkdir test_php_mink
cd test_php_mink/
composer require behat/mink
composer require behat/mink-zombie-driver
As a check:
test_php_mink$ ls
composer.json composer.lock vendor
... it seems all composer files are there.
Finally, as per http://mink.behat.org/en/latest/drivers/zombie.html (and also Cannot find module 'zombie' · Issue #84 · assaf/zombie · GitHub), I'm trying this script:
<?php
# composer autoload:
require_once __DIR__ . '/vendor/autoload.php';
echo "safe_mode: '" . ini_get("safe_mode") ."'\n"; # have PHP 5.5.9, safe_mode is removed
putenv("NODE_PATH=/usr/lib/node_modules");
echo "NODE_PATH is: '" . getenv ( "NODE_PATH" ) . "'\n"; # OK, is there
# NOPE:
#$driver = new \Behat\Mink\Driver\ZombieDriver();
$driver = new \Behat\Mink\Driver\ZombieDriver(
new \Behat\Mink\Driver\NodeJS\Server\ZombieServer()
);
$session = new \Behat\Mink\Session($driver);
// start the session
$session->start();
?>
This script, unfortunately, still fails with:
$ php test_php_mink.php
safe_mode: ''
NODE_PATH is: '/usr/lib/node_modules'
PHP Fatal error: Uncaught exception 'RuntimeException' with message 'Server process has been terminated: (8) [
module.js:340
throw err;
^
Error: Cannot find module 'zombie'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at Object.<anonymous> (/path/to/test_php_mink/vendor/behat/mink-zombie-driver/bin/mink-zombie-server.js:3:14)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
]' in /path/to/test_php_mink/vendor/behat/mink-zombie-driver/src/NodeJS/Server.php:413
Stack trace:
#0 /path/to/test_php_mink/vendor/behat/mink-zombie-driver/src/NodeJS/Server.php(306): Behat\Mink\Driv in /path/to/test_php_mink/vendor/behat/mink-zombie-driver/src/NodeJS/Server.php on line 413
How can I get this basic example to run?
EDIT: Played around a bit more with this, and discovered that when I specify the environment variable on the command line:
$ NODE_PATH=/usr/lib/node_modules php test_php_mink.php
safe_mode: ''
NODE_PATH is: '/usr/lib/node_modules'
PHP Fatal error: Uncaught exception 'RuntimeException' with message 'Server process has been terminated: (8) [
/usr/lib/node_modules/zombie/node_modules/jsdom/lib/jsdom/level2/html.js:238
var nonInheritedTags = new Set([
^
ReferenceError: Set is not defined
...
... then the module seems to be found! So my question basically reduces to: how can I change the NODE_PATH environment variable from my php script, so I wouldn't have to specify it on the shell - since apparently putenv("NODE_PATH=/usr/lib/node_modules"); does not really work for me...
As for the new error, there is Installing Zombie.js Error: ReferenceError: Set is not defined. What am I doing wrong? - apparently this is due to the version mismatch that I got a warning for (npm WARN engine zombie#4.2.1: wanted: {"node":"^4.0.0"} (current: {"node":"0.10.45","npm":"2.15.1"})), so I guess I'll have to install nvm so I can install the right nodejs version; and I also noticed in /usr/lib/node_modules/zombie/README.md:
Zombie 4.x is tested to work with io.js 1.6 or later.
If you need to use Node 0.12 or earlier, consider using Zombie 2.x. ...
To install Zombie.js you will need io.js:
```bash
$ npm install zombie --save-dev
```
... and I think that can also be installed with nvm; so I'll give that a try...

Ok, found some sort of a method which seemingly works - but I'd still like someone more knowledgeable to answer.
Anyways, the trick is - zombie can accept a path to the nodejs binary; so if you cannot really pass environment variables for nodejs from PHP, then make a shell script which will set these environment variables, and then call nodejs.
First this was my install:
# remove previous
sudo npm uninstall -g zombie --save-dev
sudo apt-get remove --purge nodejs && sudo apt-get autoremove --purge
# install new
curl -o- https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
nvm install iojs-v3.3.1
npm list -g --depth=0
nvm install 4.0.0
npm list -g --depth=0
npm -g install zombie --save-dev
The problem with nvm is that it installs in a user directory, and I'd like to test my scripts both on my user machine and remote server, where my uids are completely different. Regardless, using a custom executable helps a bit with that. So, create a script in a "global" location, I chose /home, so I'll need sudo to create files there:
sudo touch /home/node_pth.sh
... then paste in the following content:
#!/bin/bash
export NODE_PATH=/home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules
#echo ARGS ARE "$#" | tee -a /tmp/node.log
/home/USERNAME/.nvm/versions/node/v4.0.0/bin/node "$#"
... of course, replacing the paths with your correct ones; then finally make it executable:
sudo chmod +x /home/node_pth.sh
Now we can use the following test_php_mink.php PHP file:
<?php
$nodeModPath = "/home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules"; # correct NODE_PATH, but will not help
$nodePath = "/home/node_pth.sh"; # shell script that sets NODE_PATH, then calls node executable
echo "NODE_PATH is: '" . getenv ( "NODE_PATH" ) . "'\n"; #
putenv("NODE_PATH=".$nodeModPath);
echo "NODE_PATH is: '" . getenv ( "NODE_PATH" ) . "'\n"; # is there - but still doesn't help with call
# composer autoload:
require_once __DIR__ . '/vendor/autoload.php';
echo "safe_mode: '" . ini_get("safe_mode") ."'\n"; # have PHP 5.5.9, safe_mode is removed
$driver = new \Behat\Mink\Driver\ZombieDriver(
//~ new \Behat\Mink\Driver\NodeJS\Server\ZombieServer()
# copy defaults here for everything but nodeBin;
# see vendor/behat/mink-zombie-driver/src/NodeJS/Server.php
new \Behat\Mink\Driver\NodeJS\Server\ZombieServer("127.0.0.1", 8124, $nodePath, null)
);
$session = new \Behat\Mink\Session($driver);
// start the session
$session->start();
?>
... OR, I just realized there is setNodeModulesPath($nodeModulesPath) in vendor/behat/mink-zombie-driver/src/NodeJS/Server.php, so we can drop the proxy bash executable altogether:
<?php
$nodeModPath = "/home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules"; # correct NODE_PATH, but will not help via putenv
echo "NODE_PATH is: '" . getenv ( "NODE_PATH" ) . "'\n"; #
putenv("NODE_PATH=".$nodeModPath);
echo "NODE_PATH is: '" . getenv ( "NODE_PATH" ) . "'\n"; # is there - but still doesn't help with call
# composer autoload:
require_once __DIR__ . '/vendor/autoload.php';
echo "safe_mode: '" . ini_get("safe_mode") ."'\n"; # have PHP 5.5.9, safe_mode is removed
$zsrv = new \Behat\Mink\Driver\NodeJS\Server\ZombieServer();
$zsrv->setNodeModulesPath($nodeModPath . "/"); # needs to end with a trailing '/'
$driver = new \Behat\Mink\Driver\ZombieDriver( $zsrv );
$session = new \Behat\Mink\Session($driver);
// start the session
$session->start();
?>
Anyways, when this script is called, it outputs:
$ php test_php_mink.php
NODE_PATH is: ''
NODE_PATH is: '/home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules'
safe_mode: ''
... and as there are no errors, I'm assuming it is all fine now...

Related

Google sign-in migration to Google Cloud Run

I successfully implemented Google's sign-in feature which is running quite nicely on my local machine (Mac, PHP, MySQL) following these instructions. I posted how I implemented this here.
I have recently uploaded the work-in-progress site to a container in a Google Cloud Run environment but this sign-in feature is no longer working. The error log shows: PHP Fatal error: Uncaught Error: Failed opening required '/var/www/html/vendor/autoload.php' (include_path='.:/usr/local/lib/php') in /var/www/html/includes/oauth.php:5.
I've take this to mean that the /vendor/... dependencies are either in a different location, or not there at all (I exclude these files from the deployment, though I do include the composer.json file which requires the google/apiclient) and I can't figure out if there is a simple configuration I need to perform to tell the Cloud Run service about the dependency.
I'm getting very lost in the Google documentation. One track suggests that I should abandon this method and move to Google Identity Services Library which would be quite frustrating as I spent quite some effort getting the current method working correctly.
The javascript components work well and produce a pop-up to allow the user to select their Google ID and log in. The callback function works too as the oauth.php file is executed on the server and it outputs to the console the sessionId. It's just the require_once line that's causing the failure.
// oauth.php
<?php
session_start();
error_log("oauth.php SessionId: " . session_id(), 0);
include 'connect.php';
require_once __DIR__ . '/vendor/autoload.php';
$jwt = new \Firebase\JWT\JWT; //Allow for discrepancies between server and auth times
$jwt::$leeway = 100;
$CLIENT_ID = "XXX";
$client = new Google_Client(['client_id' => $CLIENT_ID]); // Specify the CLIENT_ID of the app that accesses the backend
$client->setRedirectUri('postmessage');
$client->addScope("email");
$client->addScope("profile");
if (isset($_POST['idtoken'])){
$id_token = $_POST['idtoken'];
// Code continues to validate and process the user data
}
Has anyone experienced this challenge and found a resource to help with migrating a google sign-in service from a standalone apache-based deployment to Google Cloud Run?
My Dockerfile (which doesn't contain any information about composer. I'm now reading that I need to perform a composer install either within this Dockerfile or within docker-compose):
# Use the official PHP image.
# https://hub.docker.com/_/php
FROM php:8.0-apache
# Configure PHP for Cloud Run.
# Precompile PHP code with opcache.
RUN docker-php-ext-install -j "$(nproc)" opcache
RUN docker-php-ext-install -j "$(nproc)" mysqli
RUN set -ex; \
{ \
echo "; Cloud Run enforces memory & timeouts"; \
echo "memory_limit = -1"; \
echo "max_execution_time = 0"; \
echo "; File upload at Cloud Run network limit"; \
echo "upload_max_filesize = 32M"; \
echo "post_max_size = 32M"; \
echo "; Configure Opcache for Containers"; \
echo "opcache.enable = On"; \
echo "opcache.validate_timestamps = Off"; \
echo "; Configure Opcache Memory (Application-specific)"; \
echo "opcache.memory_consumption = 32"; \
} > "$PHP_INI_DIR/conf.d/cloud-run.ini"
# Copy in custom code from the host machine.
WORKDIR /var/www/html
COPY . ./
# Use the PORT environment variable in Apache configuration files.
# https://cloud.google.com/run/docs/reference/container-contract#port
RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
# Configure PHP for development.
# Switch to the production php.ini for production operations.
# RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# https://github.com/docker-library/docs/blob/master/php/README.md#configuration
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
composer.json:
{
"require": {
"google/apiclient": "^2.11"
}
}
I added the following to the end of my Dockerfile. I added the USER line as I was getting a "An error was encountered loading IAM roles associated with the service acount[sic]." error. This user has the following roles: Cloud Run Admin, Secret Manager, Service Accounts, Cloud Build. I'm still getting build failures, probably because I'm not using the user correctly. I read that composer wants to install as root which causes problems during a cloud build:
FROM composer as builder
WORKDIR /app/
USER XXX#cloudbuild.gserviceaccount.com
COPY composer.* ./
RUN composer install
COPY --from=builder /app/vendor /var/www/html/vendor

Why Bref cannot load bootstrap: "Error: Couldn't find valid bootstrap(s): [/var/task/bootstrap /opt/bootstrap]"?

I am investigating on how I can create an AWS lambda in php using the bref library
Therefore, according to documentation I set up the environment with the following command cocktail:
sudo -H npm install -g serverless
composer require bref/bref
Then using the following command created my first php lambda:
vendor/bin/bref init
And I selected the first option PHP Function provided by default. Creating the following creating an index.php file:
declare(strict_types=1);
require __DIR__.'/vendor/autoload.php';
lambda(function ($event) {
return 'Hello ' . ($event['name'] ?? 'world');
});
Then I changed my serverless.yml into that:
service: app
provider:
name: aws
region: eu-central-1
runtime: provided
stage: ${opt:stage,'local'}
package:
exclude:
- '.gitignore'
plugins:
- ./vendor/bref/bref
functions:
dummy:
handler: index.php
name: Dummy-${self:provider.stage}
description: 'Dummy Lambda'
layers:
- ${bref:layer.php-73}
And I try to launch it via the following command:
sls invoke local --stage=local --docker --function dummy
But I get the following error:
{"errorType":"exitError","errorMessage":"RequestId: 6403ebee-13b6-179f-78cb-41cb2f517460 Error: Couldn't find valid bootstrap(s): [/var/task/bootstrap /opt/bootstrap]"}
Therefore, I want to ask why I am unable to run my lambda localy?
Since this question is getting a lot of views, I recommend to have a look at the Bref documentation:
Local development for PHP functions
That involves using the bref local CLI command instead of serverless invoke local:
$ vendor/bin/bref local hello
Hello world
# With JSON event data
$ vendor/bin/bref local hello '{"name": "Jane"}'
Hello Jane
# With JSON in a file
$ vendor/bin/bref local hello --file=event.json
Hello Jane
On my local, clearing cache before invoking lambda worked fine, I'm using linux / ubuntu
docker system prune --all
sudo apt-get autoremove
sudo apt-get clean
sudo apt-get autoclean
sudo rm -rf ~/.cache/
sudo rm -rf /var/cache/
It is a known bug for bref. It can be solved via providing the layer manually on your function in serverless.yml. So the functions section at serverless.yml should change from:
functions:
dummy:
handler: index.php
name: Dummy-${self:provider.stage}
description: 'Dummy Lambda'
layers:
- ${bref:layer.php-73}
Into:
functions:
dummy:
handler: index.php
name: Dummy-${self:provider.stage}
description: 'Dummy Lambda'
layers:
- 'arn:aws:lambda:eu-central-1:209497400698:layer:php-73:15'
The reason why is that ${bref:layer.php-73} cannot be resolved into a php layer. Therefore, you need to provide manually the arn for the lambda layer.
Keep in mind that the arn comes into various "versions" that is being inidcated from the last number in the arn seperated with :. So in the arn
arn:aws:lambda:eu-central-1:209497400698:layer:php-73:15
Indicated that the layer is in version "15" whitch is thje latest at the moment of the answer. The next one logically should be the:
arn:aws:lambda:eu-central-1:209497400698:layer:php-73:16

Run mjml cli using symfony process

I've installed mjml cli using the following command (as described in the mjml documentation):
npm install mjml --save
now if i did node_modules/.bin/mjml in the command line it will run successfully.
the problem is when i use the symfony process component in php i got the following error (even if it's the right path):
The command "/Users/qoraiche/Documents/my-app/node_modules/.bin/mjml" failed. Exit Code: 127(Command not found) Working directory: /Users/qoraicheOS/Documents/my-app/public Output: ================ Error Output: ================ env: node: No such file or directory
Symfony process code:
$process = new Process(base_path('node_modules/.bin/mjml'));
$process->run();
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}
echo $process->getOutput();
By the way i have installed mjml globally as well and try it with no luck.
Try providing the full path to node.js when calling the MJML binary from a Symfony Process().
$process = new Process('/your/path/to/node ' . base_path('node_modules/.bin/mjml'));
I use this method in my own apps. Of course, you will need to provide the input and output files to actually transpile anything.

Fatal error: Uncaught Error: Class 'LanguageClient' not found

just using playing around with Google's Natural Language API with php, but I can't seem to run a simple example.
Here is the basic for my php:
<?php
# Imports the Google Cloud client library
use Google\Cloud\Language\LanguageClient;
# Your Google Cloud Platform project ID
$projectId = '<My Project Name>';
# Instantiates a client
$language = new LanguageClient([
'projectId' => $projectId
]);
# The text to analyze
$text = 'Hello, world!';
# Detects the sentiment of the text
$annotation = $language->analyzeSentiment($text);
$sentiment = $annotation->sentiment();
echo 'Text: ' . $text . 'Sentiment: ' . $sentiment['score'] . ', ' . $sentiment['magnitude'];
?>
But it comes up with this error:
Fatal error: Uncaught Error: Class 'LanguageClient' not found in /User/zan/Zan/classifier/test.php:11
Stack trace:
#0 {main}
thrown in /Users/zan/Zan/classifier/test.php on line 11
I used composer to install google/cloud, but have no clue why it's unable to find LanguageClient. Can anyone point me in the right direction?
Did you include the composer autoloader?
include __DIR__ . "/vendor/autoload.php";
This example assumes you ran composer install in the same directory your code is running. Modify the path accordingly to match your configuration.
just a quick update, so I managed to get it working in the end. Since it was a new laptop, most of my php files weren't setup correctly.
I was missing these components:
autoconf
pecl
php-unit
grpc
protobuf
pcre
Lastly, running a
composer update
within the directory and adding the header
include __DIR__ . "/vendor/autoload.php";
I then ran the script and it worked, thanks to jdp for add and Martin for the heads up.

How to install mailgun in PHP?

This is how I install mailgun on a VM that runs PHP:
# Install Composer
curl -sS https://getcomposer.org/installer | php
# Add Mailgun as a dependency
php composer.phar require mailgun/mailgun-php:~2.0
# Add Guzzle 6 as a dependency
php composer.phar require php-http/guzzle6-adapter:^1.1.1
But when I load a page with this content:
<?php
require_once('/app/mailgun-php/vendor/autoload.php');
echo 'Current PHP version: ' . phpversion();
ini_set('display_errors' , 'On');
$client = new \Http\Adapter\Guzzle6\Client();
$mailgun = new \Mailgun\Mailgun('123', $client);
# use Mailgun\Mailgun;
?>
I get the following error:
Current PHP version: 5.5.9-1ubuntu4.14
Fatal error: Class 'Http\Adapter\Guzzle6\Client' not found in /app/sign-in.php on line 5
What is wrong with the installation?
You need to include the Composer autoloader so PHP knows where the Mailgun Client class actually is:
<?php
require_once('vendor/autoload.php');
echo 'Current PHP version: ' . phpversion();
ini_set('display_errors' , 'On');
$client = new \Http\Adapter\Guzzle6\Client();
?>

Categories