I'm using a library which take as a parameter a file to open it with fopen and read it with fseek and fread
Here what the constructor look like :
public function __construct($file) {
$this->file = $file;
$this->h = fopen($this->file, "r");
$stats = fstat($this->h);
$this->size = $stats['size'];
}
The data which i like to give to this constructor come from a database, so basically i have a variable with some text in it.
Is there a way to emulate a file from the variable containing the data ?
I have tried to use stream with php://memory without any luck ($stats = fstat($this->h) = 0) :
$data = " my string data";
$virtualfile = 'php://memory';
$h = fopen($path, "rw+");
fwrite($h, $data);
$lib = new MyLib($virtualfile);
Any ideas ?
Thanks
You can use the data: url wrapper
$data = " my string data";
$virtualfile='data:text/plain;base64,'.base64_encode($data);
$lib = new MyLib($virtualfile);
fopen returns you a $h pointer to the file - you should pass this pointer to your class to keep working on it, so:
$lib = new MyLib($h);
and constructor:
public function __construct($h) {
$this->h = $h;
$stats = fstat($this->h);
$this->size = $stats['size'];
}
Related
Here has a question: I need execute a task to put many data to another mysql database per minute; if the first task hasn't finish, the second has start; so,there has a multiple concurrent problem; how to resolve the problem??
I have some ideas, first, Let the task has a execute-time which less than the start time of next task;second, let the task support multi-process; but,i don't the how to write the code?
public function execute(Input $input, Output $output)
{
$tele_data = Telesales::field('*')->where([['create_time','<',time()-48*3600],['customer_label','in',[2,6,7]],['virtual_sale','=','0']])->whereRaw('phone is not null')->select()->toArray();
foreach($tele_data as $key=>$value) {
static::pushTeleToIdc($value);
}
}
private static function pushTeleToIdc($data = []) {
$res = Telesales::where('id',$value['id'])->update(['virtual_sale'=>'1']);
if(!$res) {
return;
}
$url = config('idc.tele_url');
$key = config('idc.tele_key');
$channel = config('idc.tele_channel');
$time = time();
$sign = md5($key.$channel.$time);
$urls = $url."?channel=".$channel."&sign=".$sign."&time=".$time;
$require_params = config('idc.require_params');
foreach($require_params as $key=>$value) {
if(array_key_exists($key,$data) && !empty($data[$key])) {
$d[$key] = $data[$key];
}else{
$d[$key] = empty($value)?'':$value[array_rand($value,1)];
}
}
$d['register_time'] = $d['create_time'];
$res = post_url($urls,$d);
$result = json_decode($res,true);
if (isset($result['code']) && $result['code'] != 0){
Log::init(['single'=>'tpushidc'])->error($res);
}
}
Could you help me resolve the problem?
The easiest thing to do is to setup a flag to tell that the process is already in progress and check if that's the case at the start of the function. I don't know how you want to setup the visibility of your code, so I leave it to you to extract $myFile to the file/class scope (same goes for the file path, you probably want to use some /var or /log folder for such stuff).
So the gist is: we create a file, if it doesn't exist or there is a 0 in it - it means we can start working. On other hand, if the contents of the file is 1, the process will die and it will be so every time you run it, until the first one finishes and rewrites the contents of the file to 0 (which means the process is not in progress anymore).
public function execute(Input $input, Output $output)
{
if ($this->isProcessInProgress()) {
die('Process is in progress');
}
$this->startProcess();
$tele_data = [...];
foreach($tele_data as $key=>$value) {
static::pushTeleToIdc($value);
}
$this->finishProcess();
}
private function isProcessInProgress() {
$myFile = 'tele_to_idc_process.txt';
$handle = fopen($myFile, 'r');
if (!$handle)
return false;
$status = fread($handle, 1);
fclose($handle);
return (bool) $status;
}
private function startProcess() {
$myFile = 'tele_to_idc_process.txt';
$handle = fopen($myFile, 'w');
if (!$handle)
return;
$status = fwrite($handle, '1');
fclose($handle);
}
private function finishProcess() {
$myFile = 'tele_to_idc_process.txt';
$handle = fopen($myFile, 'w');
if (!$handle)
return;
$status = fwrite($handle, '0');
fclose($handle);
}
You might get a warning if the file doesn't exist, you can suppress it with #fopen instead of fopen
So I have a function that I CANNOT get to work. What's happening is it's coming back with data that's in binary and not the actual file. However, in the binary that I get back, the name of the particular file is included in the string. The data looks like this:
PK‹Mpt-BR/finalinport.html³)°S(ÉÈ,V¢‘ŒT…‚ü¢’ÒôÒÔâT…´Ì¼Ä ™” “I,QðT(ÏÌÉQ(-ÈÉOLQH„¨‡*Ê/B×]’X”žZ¢`£_`ÇPK.Ùô LePK‹M.Ùô Lept-BR/finalinport.htmlPKD
pt-BR is the directory and the 'finalinport.html' is the file that I am trying to have downloaded. If I replace the second parameter of fwrite to just a plain string, then everything works and I get the string that I wrote in a file inside of the zip. But not when I'm using Stream->getContents(), which leads me to believe that it is something going on with the stream. I cannot wrap my head around what can be happening. I've been on this for a week and a half now so any suggestions would be great.
public function downloadTranslations(Request $request, $id)
{
$target_locales = $request->input("target_locale");
$has_source = $request->input("source");
$client = new API(Auth::user()->access_token, ZKEnvHelper::env('API_URL', 'https://myaccount.com'));
$document = Document::find($id);
$job_document = JobDocument::where('document_id', $id)->first();
$job = Job::find($job_document->job_id);
$file = tempnam('tmp', 'zip');
$zip = new ZipArchive();
$zip->open($file, ZipArchive::OVERWRITE);
$name_and_extension = explode('.', $document->name);
if($target_locales == null){
$target_locales = [];
foreach ($job->target_languages as $target_language) {
$target_locales[] = $target_language['locale'];
}
}
foreach($target_locales as $target_locale){
$translation = $client->downloadDocument($document->document_id, $target_locale);
$filename = $name_and_extension[0] . ' (' . $target_locale . ').' . $name_and_extension[1];
if($translation->get('message') == 'true') {
//API brings back file in stream type
$stream = Stream::factory($translation->get('body'));
$newFile = tempnam(sys_get_temp_dir(), 'lingo');
$handle = fopen($newFile, 'w');
fwrite($handle, $stream->getContents());
$zip->addFile($newFile, 'eh.html');
fclose($handle);
}
else if($translation->get('message') == 'false'){
//API brings back file contents
$zip->addFromString($filename, $translation->get('body'));
}
}
$translation = $client->downloadDocument($document->document_id, null, null);
$filename = $name_and_extension[0]. ' (Source).'.$name_and_extension[1];
$zip->addFromString($filename, $translation->get('body'));
sleep(10);
$zip->close();
return response()->download($file, $name_and_extension[0].'.zip')->deleteFileAfterSend(true);
}
I'm unfamiliar with PHP streams and I don't have a debugger set up so I keep thinking it has something to do with how I am handling the stream. Because the other condition (the else if) is coming back as content of the file (string) and the if statement, the data is coming back as a stream resource, which I am unfamiliar with.
Stream::factory
is used in Guzzle 5, use json_encode for Guzzle 6.
So I need to create a dynamic text file based on the name of a variable in php (ex: dynamicName.txt). I then need to write other variables in the file.
$testVar = "test.txt";
function sendCalc(){
global $testVar;
$objCalcTxt = ("C:\\xampp\\htdocs\\test.new\\upload\\$testVar");
$fp = fopen($objCalcTxt, 'x');
fwrite($fp, "Test\n");
fclose($fp);
When I do the above, the file is created with no problem, and all the data is written successfully. However, this is not a dynamic file name.
$objName = "dynamicName";
$ext = ".txt"
$dynamicNameTxt = $objName.$ext;
function sendCalc(){
global $objName;
global $ext;
global $dynamicNameTxt;
$objCalcTxt = ("C:\\xampp\\htdocs\\test.new\\upload\\$dynamicNameTxt");
$fp = fopen($objCalcTxt, 'x');
fwrite($fp, "Test\n");
fclose($fp);
When I try to concatenate the variable that contains the dynamic file name ($objName), with the $ext var, it does not want to create the file.
I echoed the $dynamicName var and it returns dynamicName.txt, so why doesn't this work with fopen. Essentially it has to be a problem with the concatenation right? If so, can I either concatenate a different way, or use a different method to open/create the file?
All help/ideas are appreciated.
I do not really know what you're trying to achieve with the line
$objCalcTxt = ("C:\\xampp\\htdocs\\test.new\\upload\\$dynamicNameTxt");
if from what i understand it should just be a string:
$objCalcTxt = "C:\\xampp\\htdocs\\test.new\\upload\\".$dynamicNameTxt;
Also I'd suggest you provide the needed variables as arguments for the function insted of using globals
function sendCalc($objName, $ext, $dynamicNameTxt){
...
}
You are declaring the global variables inside your function. This could destroy their initial values.
Instead of using global variables in your function, rather pass the variables as arguments:
$objName = "dynamicName";
$ext = ".txt"
$dynamicNameTxt = $objName.$ext;
function sendCalc(objName, $ext, $dynamicNameTxt)
{
$objCalcTxt = ("C:\\xampp\\htdocs\\test.new\\upload\\$dynamicNameTxt");
$fp = fopen($objCalcTxt, 'x');
fwrite($fp, "Test\n");
fclose($fp);
}
Your other option is to specifically call the global variable:
global $objName;
global $ext;
global $dynamicNameTxt;
$objName = "dynamicName";
$ext = ".txt"
$dynamicNameTxt = $objName.$ext;
function sendCalc()
{
$objCalcTxt = ("C:\\xampp\\htdocs\\test.new\\upload\\".$GLOBAL['dynamicNameTxt']);
$fp = fopen($objCalcTxt, 'x');
fwrite($fp, "Test\n");
fclose($fp);
}
I use this often and would like to turn it into a function:
$f = fopen('../images/snotel/'. $name .'.pdf','w+');
fwrite($f, $pdf);
fclose($f);
$conv='/usr/bin/convert../images/snotel/'. $name .'.pdf ../images/snotel/'. $name .'.jpg';
system ($conv);
This is what I've tried but it doesn't seem to work:
function pdf2jpg($name)
{
$f = fopen('../images/snotel/'. $name .'.pdf','w+');
fwrite($f, $pdf);
fclose($f);
$conv='/usr/bin/convert../images/snotel/'. $name .'.pdf ../images/snotel/'. $name .'.jpg';
system ($conv);
}
...
pdf2jpg('wsr');
As it is, your function tries to write the file with no data in the $pdf variable, because you did not pass it in.
You need to do one of two things:
This version takes the PDF data as an argument and creates the file in the function:
function pdf2jpg ($pdf, $name) {
$f = fopen('../images/snotel/'.$name.'.pdf','w');
fwrite($f,$pdf);
fclose($f);
$conv = '/usr/bin/convert ../images/snotel/'.$name.'.pdf ../images/snotel/'.$name.'.jpg';
//run
system($conv);
}
// Usage
pdf2jpg($pdf, 'wsr');
This version just takes the name, assuming that the file already exists:
function pdf2jpg ($name) {
$conv = '/usr/bin/convert ../images/snotel/'.$name.'.pdf ../images/snotel/'.$name.'.jpg';
//run
system ($conv);
}
// Usage
$name = 'wsr';
$f = fopen('../images/snotel/'.$name.'.pdf','w');
fwrite($f,$pdf);
fclose($f);
pdf2jpg($name);
I have a function:
function open($file){
return fopen($file, 'w');
}
This is then called by:
function write($file,$text){
$h = $this->open($file);
fwrite($h,$text);
}
This doesn't work. It returns that fwrite was given an invalid resource stream.
This:
function open($file){
$h = fopen($file, 'w');
return $h;
}
Works fine, but I can't figure out why assigning a variable first works and directly returning fopen() doesn't.
Does it have something to do with the fact that you're within an object? The following script works for me:
<?php
function open($file) {
return fopen($file, 'w');
}
function write($file, $text) {
$h = open($file);
fwrite($h, $text);
}
write("test.txt", "hello\n");
?>
I'm running PHP 5.2.8 on Mac OS X 10.5.7.
It's probably just because you are working in the scope of an object, so it cleans up the resource stream too early - since it passes a resource stream byref, if you have a variable set, its byref'ing the variable instead of trying to do it to the resource stream - so it'll work.
declare a
var $file
then
$this->file = fopen(...)
return $this->file;
this will works because the $file variable has still a reference.