I'm using longman/telegram-bot package at my Yii2 project.
class GenericmessageCommand extends SystemCommand
{
/**
* #var string
*/
protected $name = 'genericmessage';
/**
* #var string
*/
protected $description = 'Handle generic message';
/**
* #var string
*/
protected $version = '1.0.0';
/**
* Main command execution
*
* #return ServerResponse
*/
public function execute(): ServerResponse
{
$message = $this->getMessage();
if (in_array($message->getType(), ['audio', 'document', 'photo', 'video', 'voice'])) {
$doc = call_user_func([$message, 'get' . $message->getType()]);
($message->getType() === 'photo') && $doc = end($doc);
$photoId = $doc->file_id;
$download_path = $this->telegram->getDownloadPath();
$file = Request::getFile(['file_id' => $photoId]);
if ($file->isOk() && Request::downloadFile($file->getResult())) {
return $this->replyToChat(' file is located at: ' . $download_path . '/' . $file->getResult()->getFilePath());
} else {
return $this->replyToChat('Failed to download.');
}
}
}
}
Just like that
It working fine when I'm using getUpdates method https://github.com/php-telegram-bot/core#getupdates-installation
But it doesn't work when I use WebHooks. Even though I get the same answer from my bot... It says "Ok" and "file is located at...", but there is no such file.
that because of webhook using backend of Yii2 advanced.... it stores all files at backend (because my webhook looking on backend), but i searching them at frontend (bacause i'm stupid).
Related
I currently have a symfony project that uses Foundation for Emails to create responsive emails.
The Foundation framework uses the command 'npm run build' to tranform files. I tried doing a service parse my content using the Process class but I must be using it wrong as it does not execute 'npm run build'. Here is my faulty code :
<?php
/**
* Created by PhpStorm.
* User: jeremie
* Date: 28/12/17
* Time: 16:59
*/
namespace Acme\Open4XMLParserBundle\Services;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Process\Process;
/**
* #todo : code this
*/
class FoundationParser
{
protected $foundationLocation;
protected $process;
/**
* FoundationParser constructor.
* #param $foundationLocation
*/
public function __construct($foundationLocation)
{
$this->foundationLocation = $foundationLocation;
$this->process = new Process('npm run build', $this->foundationLocation);
}
/**
* Run npm run build if needed
*/
public function initFoundation()
{
//make sure that 'npm run build' is running and execute it if not
if (!$this->process->isRunning()) {
$this->process->start();
}
}
public function saveFoundationContent($foundationContent, $filename)
{
//save the file in foundation/src/pages
$fileSystem = new Filesystem();
$fileLocation = $this->foundationLocation . '/src/pages/' . $filename;
if (!$fileSystem->exists($fileLocation)) {
$fileSystem->dumpFile($fileLocation, $foundationContent);
$fileSystem->chmod($fileLocation, 0664);
}
}
public function retrieveValidHtml($fileName)
{
$fileLocation = $this->foundationLocation . '/dist/' . $fileName;
while (true) {
try {
$result = file_get_contents($fileLocation);
if ($result !== false){
return $result;
}
} catch (\Exception $e) {
}
}
}
}
And I use my service like this :
$foundationParser = $this->container->get('open4xmlparser.foundationparser');
$foundationParser->initFoundation();
$foundationParser->saveFoundationContent($foundationContent, 'test.html');
$response = new Response($foundationParser->retrieveValidHtml('test.html'));
$response->headers->set('Content-Type', 'text/html');
$response->send();
And it tells me that 'test.html' does not exist. Any idea on how to do what I want?
What I finally decided to do is a Symfony command that launch my program in an infinite loop(it is never supposed to stop). Instead of using a service I executed 'npm run build' directly in the while loop.
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln([
'',
'Running program',
'===============',
''
]);
$runBuild = new Process('npm run build', $this->getContainer()->getParameter('foundation_location'));
while (true) {
if (!$runBuild->isRunning()){
$output->writeln([
'',
'Executing npm run build',
''
]);
$runBuild->start();
}
}
}
You seem to have different paths in the saveFoundationContent and retrieveValidHtml for the target file.
// saveFoundationContent()
$fileLocation = $this->foundationLocation . '/src/pages/' . $filename;
// retrieveValidHtml()
$fileLocation = $this->foundationLocation . '/dist/' . $fileName;
Obviously, retrieveValidHtml() cannot find the file in the location.
Tip: Store the subdirectory path as a class variable (or constant):
class FoundationParser
{
private $subdir = "/dist/"; // or "/src/pages/";
…
public function retrieveValidHtml($fileName)
{
$fileLocation = sprintf("%s%s%s", $this->foundationLocation, $this->subdir, $fileName);
…
}
}
On Owncloud 8.1 using the owncloud command line, I create a new test app:
ocdev startapp MyApp --email mail#example.com --author "Your Name" --description "My first app" --owncloud 8
The app is working, I can add it in the owncloud control panel.
Now I'd like to write to a file, so I use one example from the owncloud documentation:
https://doc.owncloud.org/server/8.1/developer_manual/app/filesystem.html
[Edit] I started over and now, I don't know if I omitted something, but "myapp" comes with no "application.php" file.
So I create it at /var/www/core/apps/myapp/appinfo/application.php :
<?php
namespace OCA\MyApp\AppInfo;
use \OCP\AppFramework\App;
use \OCA\MyApp\Storage\AuthorStorage;
class Application extends App {
public function __construct(array $urlParams=array()){
parent::__construct('myapp', $urlParams);
$container = $this->getContainer();
/**
* Storage Layer
*/
$container->registerService('AuthorStorage', function($c) {
return new AuthorStorage($c->query('RootStorage'));
});
$container->registerService('RootStorage', function($c) {
return $c->query('ServerContainer')->getRootFolder();
});
}
}
Then I create a file called /var/www/core/apps/myapp/storage/AuthorStorage.php with:
<?php
namespace OCA\MyApp\Storage;
class AuthorStorage {
private $storage;
public function __construct($storage){
$this->storage = $storage;
}
public function writeTxt($content) {
// check if file exists and write to it if possible
try {
try {
$file = $this->storage->get('/myfile.txt');
} catch(\OCP\Files\NotFoundException $e) {
$this->storage->touch('/myfile.txt');
$file = $this->storage->get('/myfile.txt');
}
// the id can be accessed by $file->getId();
$file->putContent($content);
} catch(\OCP\Files\NotPermittedException $e) {
// you have to create this exception by yourself ;)
throw new StorageException('Cant write to file');
}
}
}
The sample app already gives me a route to the index function in the pagecontroller.php
['name' => 'page#index', 'url' => '/', 'verb' => 'GET']
How do I call the function "writeTxt" from there?
Based on http://php.net/manual/en/language.oop5.basic.php
I tried:
use \OCA\MyApp\Storage\AuthorStorage;
and
public function index() {
//added part
$a = new AuthorStorage();
$a->writeTxt('test');
//original part
$params = ['user' => $this->userId];
return new TemplateResponse('myapp', 'main', $params); //templates/main.php
}
After running I get a "Class 'OCA\MyApp\Storage\AuthorStorage' not found at /var/www/core/apps/myapp/controller/pagecontroller.php#44"
Even with the help of use \OCA\MyApp\Storage\AuthorStorage; ( ClassNotFoundException: Attempted to load class... Symfony ) it doesn't seem to help.
Thanks
Time has gone by, so I'm posting an answer to my question for owncloud 9.
Here are the steps to a basic script with read, write, copy file ability.
"application.php" has definitively been removed from the example. It was not a bug.
Following:
https://doc.owncloud.org/server/9.0/developer_manual/app/startapp.html
Generate the demo "MyApp" app:
ocdev startapp MyApp --email mail#example.com --author "Your Name" --description "My first app" --owncloud 9
Edit the file myapp/controller/pagecontroller.php
<?php
/**
* ownCloud - myapp
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* #author Your Name <mail#example.com>
* #copyright Your Name 2016
*/
namespace OCA\MyApp\Controller;
use OCP\IRequest;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Controller;
use OCP\Files\IRootFolder;
use OC\Files\Storage\Temporary;
class PageController extends Controller {
private $userId;
private $storage;
private $userstorage;
public function __construct($AppName, IRequest $request, IRootFolder $storage, $UserId){
parent::__construct($AppName, $request);
$this->storage = $storage;
$this->userId = $UserId;
$this->userstorage = $this->storage->get($this->userId.'/files/');
}
/**
* CAUTION: the #Stuff turns off security checks; for this page no admin is
* required and no CSRF check. If you don't know what CSRF is, read
* it up in the docs or you might create a security hole. This is
* basically the only required method to add this exemption, don't
* add it to any other method if you don't exactly know what it does
*
* #NoAdminRequired
* #NoCSRFRequired
*/
public function index() {
$listedudossier = $this->userstorage->getDirectoryListing();
//list all items in the root directory
//and copies the files in an directory called old
//the directory "old" is not script created
foreach ($listedudossier as $value) {
if ( $value->getType() == 'file' ){
$value->copy($this->userId.'/files/old/'.$value->getName());
//also works
//$value->copy($this->userstorage->getPath().'/old/'.$value->getName());
}
}
$params = ['listedudossier' => $listedudossier ];
return new TemplateResponse('myapp', 'main', $params); // templates/main.php
}
/**
* Simply method that posts back the payload of the request
* #NoAdminRequired
*/
public function doEcho($echo) {
//creates a file
$this->userstorage->newFile('myfile2.txt');
//opens a file, adds inputbox content and saves the file
$file = $this->userstorage->get('myfile.txt');
$contenu = $file->getContent();
$file->putContent($contenu.$echo);
return new DataResponse(['echo' => $echo]);
}
}
You also need to edit the myapp/templates/part.content.php
<p>Hello World <?php p($_['user']) ?></p>
<p><button id="hello">click me</button></p>
<p><textarea id="echo-content">
Send this as ajax
</textarea></p>
<p><button id="echo">Send ajax request</button></p>
Ajax response: <div id="echo-result"></div>
<p>listedudossier:<p> <?php
foreach ($_['listedudossier'] as $file) {
echo "type:".$file->getType();
echo "<p>";
echo "nom:".$file->getName();
echo "<p>";
echo "modif:".$file->getMTime();
echo "<p>";
}
From here you can test the code in a development environment:
https://github.com/owncloud/ocdev/blob/master/README.rst#installation
I would like to use YUI compressor with minify PHP rather than the default JSmin. Does anyone have experience setting this up?
Right now I am using the groupsConfig.php to combine the JS.
return array(
'jsAll' => array('//contenido/themes/bam/assets/js/jquery.js', '//contenido/themes/bam/assets/js/modernizr.js','//contenido/themes/bam/assets/js/imgpreload.js', '//contenido/themes/bam/assets/js/imgpreload.js', '//contenido/themes/bam/assets/js/history.js','//contenido/themes/bam/assets/js/ajaxify.js', '//contenido/themes/bam/assets/js/isotope.js'),
'jsHome' => array('//contenido/themes/bam/assets/js/easing.js','//contenido/themes/bam/assets/js/scrollable.js', '//contenido/themes/bam/assets/js/home.js'),
'cssAll' => array('//contenido/themes/bam/bam.css'),
);
As it says on the homepage:
Uses an enhanced port of Douglas Crockford's JSMin library and custom classes to minify CSS and HTML
I have the following code in config.php, but I get a 500 error when trying to view the combined js file:
function yuiJs($js) {
require_once '/lib/Minify/YUICompressor.php';
Minify_YUICompressor::$jarFile = '/lib/yuicompressor-2.4.2.jar';
Minify_YUICompressor::$tempDir = '/temp';
return Minify_YUICompressor::minifyJs($js);
}
$min_serveOptions['minifiers']['application/x-javascript'] = 'yuiJs';
It also appears that there are several lines in lib/Minify/YUICompressor.php that need to be configured, and I'm not sure if I'm doing it right:
class Minify_YUICompressor {
/**
* Filepath of the YUI Compressor jar file. This must be set before
* calling minifyJs() or minifyCss().
*
* #var string
*/
public static $jarFile = '../yuicompressor-2.4.2.jar';
/**
* Writable temp directory. This must be set before calling minifyJs()
* or minifyCss().
*
* #var string
*/
public static $tempDir = '../../temp/';
/**
* Filepath of "java" executable (may be needed if not in shell's PATH)
*
* #var string
*/
public static $javaExecutable = 'java';
I had the same problem on windows. It seems jar file needs to be executable in order to run yui compressor. So, i have to remove excutable check from YUICompressor.php
#132
private static function _prepare()
{
if (! is_file(self::$jarFile)) {
throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not a valid file.');
}
// if (! is_executable(self::$jarFile)) {
// throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not executable.');
// }
if (! is_dir(self::$tempDir)) {
throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not a valid direcotry.');
}
if (! is_writable(self::$tempDir)) {
throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not writable.');
}
}
and that works fine.
Is (function_exists('ob_gzhandler') && ini_get('zlib.output_compression')) enough ?
I want to check if the host is serving compressed pages within one of the pages :)
For PHP, they'll do fine.
However, if your referring to compression of pages back to clients, you'll also need to check it's enabled in apache (assuming your using apache you'll need the mod_gzip.c OR mod_deflate.c modules).
For instance:
# httpd -l (apache 2)
Ive also seen mention of needing to implement .htaccess overrides in the past:
#compress all text & html:
AddOutputFilterByType DEFLATE text/html text/plain text/xml
# Or, compress certain file types by extension:
<Files *.html>
SetOutputFilter DEFLATE
</Files>
With
<?php
phpinfo();
?>
You could find if the module is loaded
or
This website https://www.giftofspeed.com/gzip-test/
You can check if the compression on a certain page is enabled.
With those you'll see if the compression is enough for you.
you can do this programmatically from php:
if (count(array_intersect(['mod_deflate', 'mod_gzip'], apache_get_modules())) > 0) {
echo 'compression enabled';
}
This is of course not super reliable, because there might be other compression modules...
I have a class that checks based on a get request to css or js file if gzip compression is enabled and then tries to output corresponding compressed css or js file if it's enabled or a regular file if it's not.
If you are looking only at how to check if gszip is enabled then isPhpGzCompressionInProcess method of these class can help you but in most cases, you need to process some output base on it and I am pretty sure that the rest of the class can help someone too.
<?php
/**
* Class AssetBundleController
*/
class AssetBundleCompressionController
{
/**
* AssetBundleController constructor.
*/
public function __construct()
{
$this->outputCompression();
}
/**
* Trying to output compression bundle.
*/
protected function outputCompression()
{
// here request to css or js file
if (empty($_GET['vcv-script']) && empty($_GET['vcv-style'])) {
return;
}
error_reporting(0);
$mimeType = $this->getMimeType();
header('Content-Type: ' . $mimeType);
if (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === false) {
// browser cannot accept compressed content, so need output standard JS/CSS
echo file_get_contents($this->getBundlePath());
} else {
if ($this->isPhpGzCompressionInProcess()) {
// let 3 party app gzip our content.
echo file_get_contents($this->getBundlePath());
} else {
// output our gzip content.
header("Content-Encoding: gzip");
echo file_get_contents($this->getBundlePath(true));
}
}
exit;
}
/**
* Get current requested bundle path.
*
* #param bool $isCompress
*
* #return string
*/
protected function getBundlePath($isCompress = false)
{
$assetType = $this->getAssetType();
$name = $this->getCompressionRequestName($assetType);
$path = VCV_PLUGIN_DIR_PATH . 'public/dist/' . $name . '.bundle.' . $assetType;
if ($isCompress) {
$path .= '.gz';
}
return $path;
}
/**
* Check if php compression is already enabled.
*
* #return bool
*/
protected function isPhpGzCompressionInProcess()
{
if (in_array('ob_gzhandler', ob_list_handlers())) {
return true;
}
// check if zlib php exention is working
if (extension_loaded('zlib')) {
#ini_set('zlib.output_compression_level', 1);
if (ini_get('zlib.output_compression_level') === '1') {
return true;
}
}
return false;
}
/**
* Get compression request name.
*
* #return string
*/
protected function getCompressionRequestName($assetType)
{
$name = '';
$compressList = [
'editor',
'wp',
'vendor',
'runtime',
];
$searchKey = $assetType === 'js' ? $_GET['vcv-script'] : $_GET['vcv-style'];
$key = array_search($searchKey, $compressList);
if ($key !== false) {
$name = $compressList[$key];
}
return $name;
}
/**
* Check current requested asset type
*
* #return string
*/
protected function getAssetType()
{
$type = 'js';
if (!empty($_GET['vcv-style'])) {
$type = 'css';
}
return $type;
}
/**
* Set current request asset mine type.
*/
protected function getMimeType()
{
$type = 'application/javascript';
if (!empty($_GET['vcv-style'])) {
$type = 'text/css';
}
return $type;
}
}
I need to send/return objects or array to/from PHP using SOAP. Any good links?
I am using Zend_Soap_Server и Zend_Soap_Client. I send/receive array of difficult structure.
At first create class with structure you want to receive.
<?php
/**
* Information about people
*/
class PeopleInformation
{
/**
* Name of ...
*
* #var string
*/
public $name;
/**
* Age of
* #var int
*/
public $age;
/**
* Array of family
*
* #var FamilyInformation[]
*/
public $family;
}
/**
* Information about his family
*/
class FamilyInformation
{
/**
* Mother/sister/bro etc
*
* #var string
*/
public $relation;
/**
* Name
* #var string
*/
public $name;
}
?>
Then create service to receive this data:
<?php
/**
* Service to receive SOAP data
*/
class SoapService
{
/**
*
* #param PeopleInformation $data
* #return string
*/
public function getUserData($data)
{
//here $data is object of PeopleInformation class
return "OK";
}
}
?>
Now create Zend_Soap_Server instance in controller by url http://ourhost/soap/:
<?php
//disable wsdl caching
ini_set('soap.wsdl_cache_enabled', 0);
ini_set('soap.wsdl_cache', 0);
$wsdl = $_GET['wsdl'];
//this generate wsdl from our class SoapService
if (!is_null($wsdl))
{
$autodiscover = new Zend_Soap_AutoDiscover('Zend_Soap_Wsdl_Strategy_ArrayOfTypeSequence');
$autodiscover->setClass('SoapService');
$autodiscover->handle();
}
//handle all soap request
else
{
$wsdlPath = 'http://ourhost/soap/?wsdl';
$soap = new Zend_Soap_Server($wsdlPath, array(
'cache_wsdl' => false
));
$soap->registerFaultException('Zend_Soap_Server_Exception');
$soap->setClass('SoapService');
$soap->handle();
}
?>
And now you get wsdl (http://ourhost/soap/?wsdl) with you structure and handle request in SoapService::getUserData. Input parametr in this method is object of PeopleInformation class
Basically you need to create a class map and pass it to your soap client. Yes it is a pain. I usually just have a method that maps the Soap Object name to PHP objects (i.e. Person => MY_Person) and only code the ones I need to by hand (i.e createdOn => DateTime).
class MY_WSHelper
{
protected static $ws_map;
public static function make_map()
{
if( ! self::$ws_map)
{
self::$ws_map = array();
//These will be mapped dynamically
self::$ws_map['Person'] = NULL;
self::$ws_map['Animal'] = NULL;
//Hard-coded type map
self::$ws_map['createdOn'] = DateTime;
self::$ws_map['modifiedOn'] = DateTime;
foreach(self::$ws_map as $soap_name => $php_name)
{
if($php_name === NULL)
{
//Map un-mapped SoapObjects to PHP classes
self::$ws_map[$soap_name] = "MY_" . ucfirst($soap_name);
}
}
}
return self::$ws_map;
}
}
Client:
$client = new SoapClient('http://someurl.com/personservice?wsdl',
array('classmap' => MY_WSHelper::make_map()));
$aperson = $client->getPerson(array('name' => 'Bob'));
echo get_class($aperson); //MY_Person
echo get_class($aperson->createdOn); //DateTime
http://php.net/manual/en/soapclient.soapclient.php
Papa Google points me to this Zend article with lots of good examples on both the client and server aspects of working with Soap (in particular PHP5's implementation of it). Looks like a good starting point.
If you're somewhat like me, and cringe at the thought of writing up a WSDL by hand, I'd recommend using WSHelper, which uses PHP's reflection classes to dynamically generate a WSDL for you. Definitely a time-saver
I replay to share my (bad) experience.
I've created a webservice using PHP ZendFramework2 (ZF2).
The server reply objects and array of objects, and until it taken string as input it worked well. I was using the ArrayOfTypeComplex strategy.
$_strategy = new \Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeComplex();
When I try to use an array of string as input I felt in a dark and unhappy valley until I found Ramil's answer, so I change strategy and all work right!
$_strategy = new \Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeSequence();
if (isset($_GET['wsdl'])) {
$autodiscover = new \Zend\Soap\AutoDiscover($_strategy);
$autodiscover->setBindingStyle(array('style' => 'document'));
$autodiscover->setOperationBodyStyle(array('use' => 'literal'));
$autodiscover->setClass('Tracker\Queue\Service')
->setUri($_serverUrl);
echo $autodiscover->toXml();
}