Форум » [x]Harbour » HBCURL » Ответить

HBCURL

Eduard: Dima пишет: [quote]Вот и все непонятки закончились после того как убил кучу времени. У DownloadFile проблема с длинными именами файлов , при чем в UploadFile этой проблемы нет. Не важно каков размер файла , важна для него длина имени файла. Прошу опровергнуть или подтвердить описанное поведение DownloadFile. [/quote] Добрый день. У меня точно такая же проблема нарисовалась в моей программе, как описывает Дима. Программа на отрез не хочет принимать с фтп длинные имена файлов. точь в точь как в этой теме http://clipper.borda.ru/?1-4-0-00000844-000-10001-0 Удалось ли Вам побороть данную проблему.? Как вышли из ситуации? Хочу перейти на HBCURL, но нужно описание всех функций, особенно получение списка файлов с фтп-сервера по маске и скачивание файлов с сервера. Поделитесь своими наработками пожалуйста. П.С. Вот кусок программы, в котором я пытаюсь скачать файлики с сервера, список получаю, а вот файл /файлы / скачать не удается... [more] curl_global_init() IF ! Empty( curl := curl_easy_init() ) DEFAULT cDL TO "ftp://"+ArmFTP+"/" curl_easy_setopt( curl, HB_CURLOPT_DOWNLOAD ) curl_easy_setopt( curl, HB_CURLOPT_DIRLISTONLY) curl_easy_setopt( curl, HB_CURLOPT_USERPWD, ArmLogin+":"+ArmPass ) curl_easy_setopt( curl, HB_CURLOPT_URL, cDL+"OUT"+"/"+ArmPostID+"/"+dt2+"/" ) curl_easy_setopt( curl, HB_CURLOPT_DL_BUFF_SETUP ) curl_easy_perform( curl ) //DOWNLOAD DIRLIST TO STRING dnfiles:= curl_easy_dl_buff_get( curl ) MsgInfo(dnfiles) curl_easy_reset( curl ) //получаю список файлов на сервере DEFAULT cDL TO "ftp://"+ArmFTP+"/" curl_easy_setopt( curl, HB_CURLOPT_DOWNLOAD ) curl_easy_setopt( curl, HB_CURLOPT_USERPWD, ArmLogin+":"+ArmPass ) curl_easy_setopt( curl, HB_CURLOPT_URL, cDL+"OUT"+"/"+ArmPostID+"/"+dt2+"/" ) curl_easy_setopt( curl, HB_CURLOPT_DL_FILE_SETUP, cFileName := "*.*" ) ??? по маске, либо через список не хочет. curl_easy_setopt( curl, HB_CURLOPT_FAILONERROR, .T. ) curl_easy_perform( curl ) MsgInfo("DOWNLOAD FILE _ FILENAME: ") а вот тут засада, файлы не скачиваются... нужна помощь. curl_easy_reset( curl ) curl_easy_cleanup( curl ) ENDIF curl_global_cleanup() [/more]

Ответов - 65, стр: 1 2 3 4 All

Петр: Я давно не собирал libcurl.dll и программ с его использованием соответственно. Попробую найти время и посмотреть. Это сделать можно, вот вариант решения Другое дело можно ли это сделать для mingw и какие телодвижения нужно совершить для этого А чем не устраивает hbtip или curl, если он с 10-й действительно поставляется? Просто интересно

Dima: Петр С DelayLoad хорошее решение Но такой фичи похоже нет в MINGW , что печально.

Dima: Петр пишет: А чем не устраивает hbtip или curl, если он с 10-й действительно поставляется? Hbtip устраивает но у ряда провайдеров UPLOAD/DOWNLOAD (особенно последний) глючит по FTP и не докачивает файлы , хотя фтп-сервер один и тот же. Игрался с CURL.EXE у таких провов и FTP , вот с ним нет проблем. Если с LIBCURL.DLL не получится как задумал , возможно придется юзать CURL.EXE Спасибо


AndreyZh: Если устроит "колхозное" решение - стал применять, обнаружив, что не закачиваются на ftp файлы с длинными именами, а именно УПД [pre] aFiles := Directory(_OUTBOX+cShab+"*.xml") aBin := Directory(_OUTBOX+cShab+"*.bin") nLen := Len(aFiles) IF nLen <= 0 THEN RETU // Выход при отсутствии файлов для сохранения на FTP // Отключена технология моей работы с FTP. Попытка открытия канала и при отказе выход из режима oFtp := TIpClientFtp():new( _ZFTP ) // Создаю экземпляр класса объекта IF !oFtp:open() THEN RETU //*** Штатные средства не умеют работать с длинными именами файлов, как у УПД - делаю через жопу IF cShab == "ON_" // 04.12.2020 Оставляю технику без изменений - добавив в условие удаление из OUTBOX == не проверяю успешность отправки oFtp:close() // Закрываю канал - соединение FOR nI := 1 TO nLen cW := "wwput.bat "+_OUTBOX+" "+aFiles[nI,1]+" "+FTP_OUTBOX RUN &cW NEXT nI // Для некоторых КА могут быть и файлы подписи. Анализирую и отправляю nBin := Len(aBin) FOR nI := 1 TO nBin cW := "wwput.bat "+_OUTBOX+" "+aBin[nI,1]+" "+FTP_OUTBOX RUN &cW NEXT nI // 04.12.2020 FOR nI := 1 TO nLen DO FileDelete( _OUTBOX+aFiles[nI,1] ) FOR nI := 1 TO nBin DO FileDelete( _OUTBOX+aBin[nI,1] ) ELSE // Старые документы и УПД от Э-КОМ сохраняю средствами программы без "моргания" [/pre] где wwput.bat wput.exe -u --reupload %1%2 ftp://name:password@adress_ftp.ru/%3/%2

Dima: Потестил HBCURL. В программе доступ с HBTIP переписал под HBCURL для доступа к FTP. Глюков нет , работает шустро и стабильно Так что для доступа к FTP , это отличный выбор. PS Проблемы со скобками в именах файлов и символом # , решены. То что лишний DLL надо с собой таскать не проблема и так тягаю DLL от ADS и PageScript

SergKis: Dima пишет Так что для доступа к FTP , это отличный выбор. Поделиться примерчиком можешь ? Сюда или сам знаешь куда. Я не осилил по времени, curl.exe с ftp опробовал и вернулся к hbtip (от примера, т.к. время поджимало)

Dima: SergKis пишет: Поделиться примерчиком можешь ? Да подготовлю

Dima: По быстрому , на коленке. [pre2] #include "fileio.ch" #include "hbcurl.ch" #include "directry.ch" proc main Local aftpPar Local LocalDir:=hb_DirSepAdd(hb_CurDrive()+":\"+CurDir()) Local cfile:="testupload.txt" local cfilezip:="__#[test]#[upload]" curl_global_init() aftpPar:=LoadNastrFtp() // загружаем настройки FTP из базы if hb_MemoWrit( LocalDir+cfile, "bla bla bla" ) if HB_ZIPFILE(LocalDir+cfilezip+".tmp",{cfile}) ferase(LocalDir+cfile) ? TestUpl(aftpPar[6],aftpPar[4],aftpPar[5],aftpPar[14],Localdir,cfilezip,"/minisklad") ferase(LocalDir+cfilezip+".tmp") endif endif curl_global_cleanup() return ************ FUNCTION TestUpl( cserver,cuser,cpassword,nport,localdir,cfile,rdir) LOCAL cUrl LOCAL lRet := .f. local aftp Local Cftp:="ftp://"+cserver+":"+hb_ntos(nport) local nas:=0 local nerr curl := curl_easy_init() if empty(curl) ? "Bad curl_easy_init" return lRet endif do while .t. curl_easy_setopt( curl, HB_CURLOPT_DOWNLOAD ) curl_easy_setopt( curl, HB_CURLOPT_URL, cftp ) curl_easy_setopt( curl, HB_CURLOPT_USERPWD,cuser+":"+cpassword) curl_easy_setopt( curl, HB_CURLOPT_FTP_USE_EPSV,0) // 0 PASV 1 EPASV curl_easy_setopt( curl, HB_CURLOPT_DL_BUFF_SETUP ) curl_easy_setopt( curl, HB_CURLOPT_QUOTE, { "CWD "+rdir} ) curl_easy_setopt( curl, HB_CURLOPT_CUSTOMREQUEST,"LIST "+cfile+".zip") * если LIST средствами CURL получать через HB_CURLOPT_DIRLISTONLY * там только имена nerr:=curl_easy_perform( curl ) if nerr#0 ? CurlError(nerr) exit endif aftp:=listfilesftp(cfile, curl_easy_dl_buff_get( curl )) // функцию слямздил в HBTIP LISTFILES // хотя можно было и свою сваять nas:=ascan(aftp,{|x| x[1]==cfile+".zip"}) ******* if nas#0 lret:=.t. exit endif curl_easy_reset( curl ) curl_easy_setopt( curl, HB_CURLOPT_UPLOAD,1 ) curl_easy_setopt( curl, HB_CURLOPT_URL,cftp+"/"+hb_StrReplace(cfile+".tmp","#",{"%23"}) ) curl_easy_setopt( curl, HB_CURLOPT_USERPWD, cuser+":"+cpassword ) curl_easy_setopt( curl, HB_CURLOPT_UL_FILE_SETUP,localdir+cfile+".tmp" ) curl_easy_setopt( curl, HB_CURLOPT_POSTQUOTE, { "RNFR " + cfile+".tmp", "RNTO " +cfile+".zip" } ) nerr:=curl_easy_perform( curl ) if nerr#0 ? CurlError(nerr) else lRet:=.t. endif exit enddo curl_easy_cleanup( curl ) RETURN lRet ******* Func ListFilesFtp( cFileSpec,clist ) LOCAL aMonth := { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } LOCAL aList, aFile, cEntry, nStart, nEnd LOCAL cYear, cMonth, cDay, cTime // LOCAL cList := ::list( cFileSpec ) IF Empty( cList ) RETURN {} ENDIF aList := hb_ATokens( cList, .T. ) FOR EACH cEntry IN aList DESCEND IF Empty( cEntry ) hb_ADel( aList, cEntry:__enumIndex(), .T. ) ELSE aFile := Array( F_LEN + 3 ) nStart := 1 nEnd := hb_At( " ", cEntry, nStart ) // file permissions (attributes) aFile[ F_ATTR ] := SubStr( cEntry, nStart, nEnd - nStart ) nStart := nEnd IF Val( StrTran( aFile[ F_ATTR ], "-" ) ) == 0 // continue with Unix format // # of links DO WHILE SubStr( cEntry, ++nStart, 1 ) == " " ENDDO nEnd := hb_At( " ", cEntry, nStart ) aFile[ F_LEN + 1 ] := Val( SubStr( cEntry, nStart, nEnd - nStart ) ) nStart := nEnd // owner name DO WHILE SubStr( cEntry, ++nStart, 1 ) == " " ENDDO nEnd := hb_At( " ", cEntry, nStart ) aFile[ F_LEN + 2 ] := SubStr( cEntry, nStart, nEnd - nStart ) nStart := nEnd // group name DO WHILE SubStr( cEntry, ++nStart, 1 ) == " " ENDDO nEnd := hb_At( " ", cEntry, nStart ) aFile[ F_LEN + 3 ] := SubStr( cEntry, nStart, nEnd - nStart ) nStart := nEnd // file size DO WHILE SubStr( cEntry, ++nStart, 1 ) == " " ENDDO nEnd := hb_At( " ", cEntry, nStart ) aFile[ F_SIZE ] := Val( SubStr( cEntry, nStart, nEnd - nStart ) ) nStart := nEnd // Month DO WHILE SubStr( cEntry, ++nStart, 1 ) == " " ENDDO nEnd := hb_At( " ", cEntry, nStart ) cMonth := StrZero( hb_AScan( aMonth, SubStr( cEntry, nStart, nEnd - nStart ), , , .T. ), 2 ) nStart := nEnd // Day DO WHILE SubStr( cEntry, ++nStart, 1 ) == " " ENDDO nEnd := hb_At( " ", cEntry, nStart ) cDay := SubStr( cEntry, nStart, nEnd - nStart ) nStart := nEnd // Year DO WHILE SubStr( cEntry, ++nStart, 1 ) == " " ENDDO nEnd := hb_At( " ", cEntry, nStart ) cYear := SubStr( cEntry, nStart, nEnd - nStart ) nStart := nEnd IF ":" $ cYear cTime := cYear cYear := StrZero( Year( Date() ), 4 ) ELSE cTime := "" ENDIF aFile[ F_DATE ] := hb_SToD( cYear + cMonth + cDay ) aFile[ F_TIME ] := cTime ELSE // DOS style/IIS format aFile[ F_LEN + 1 ] := 0 aFile[ F_LEN + 2 ] := aFile[ F_LEN + 3 ] := aFile[ F_ATTR ] := "" aFile[ F_DATE ] := hb_CToD( aFile[ F_ATTR ], "mm-dd-yy" ) // # time DO WHILE SubStr( cEntry, ++nStart, 1 ) == " " ENDDO nEnd := hb_At( " ", cEntry, nStart ) cTime := SubStr( cEntry, nStart, nEnd - nStart ) nStart := nEnd aFile[ F_TIME ] := Left( TString( Secs( Left( cTime, 5 ) ) + iif( Right( cTime, 2 ) == "PM", 43200, 0 ) ), 5 ) // file size DO WHILE SubStr( cEntry, ++nStart, 1 ) == " " ENDDO nEnd := hb_At( " ", cEntry, nStart ) aFile[ F_SIZE ] := Val( SubStr( cEntry, nStart, nEnd - nStart ) ) nStart := nEnd ENDIF // file name DO WHILE SubStr( cEntry, ++nStart, 1 ) == " " ENDDO aFile[ F_NAME ] := SubStr( cEntry, nStart ) cEntry := aFile ENDIF NEXT RETURN aList ************************** Func CurlError(n) * тут можно и расшифровку вставить по коду ошибки return "Curl_Error "+hb_ntos(n) [/pre2]

SergKis: Dima пишет По быстрому , на коленке. Спасибо Буду разбираться

Dima: SergKis Есть тонкость с HB_CURLOPT_UPLOAD и заливкой файла на FTP. Даже если curl_easy_perform уже отработал , локально заливаемый файл остается залоченным самим CURL , пока не сделаем curl_easy_reset или curl_easy_cleanup

Dima: У одного клиента мобильный инет Киевстар. Иногда при попытке подключения к FTP и получения LIST получаю ошибку CURLE_OPERATION_TIMEDOUT (28) Версия LibCurl 7.76.0 Смотрел логи FTP сервера , там все красиво , ни каких ошибок. Таймауты я не трогал. Погуглил , но решения не нашел. Не понятно как решить проблемку............. PS У всех остальных у кого нормальный инет (не мобильный) такого не возникало Возможно (не уверен) 7.76.1 решит проблему https://github.com/curl/curl/pull/6859

Dima: Каким образом перехватить то что выводит HB_CURLOPT_VERBOSE и писать в файл ? curl_easy_setopt( curl, HB_CURLOPT_VERBOSE, .t.) Пробовал HB_CURLOPT_STDERR HB_CURLOPT_FILE HB_CURLOPT_WRITEHEADER Результат нулевой........

Петр: Dima пишет: Каким образом перехватить то что выводит HB_CURLOPT_VERBOSE и писать в файл ? The verbose information will be sent to stderr, or the stream set with CURLOPT_STDERR CURLOPT_STDERR в hbcurl не реализован. Значит остается /* NOTE: Redirect STDERR to a file to see the verbose output. */ - примечание из примера к hbcurl

Петр: Петр пишет: Значит остается... Или самому написать что-то такое [pre2] static HB_GARBAGE_FUNC( FILE_release ) { void ** ph = ( void ** ) Cargo; /* Check if pointer is not NULL to avoid multiple freeing */ if( ph && *ph ) { /* Destroy the object */ fclose( ( FILE * ) *ph ); /* set pointer to NULL to avoid multiple freeing */ *ph = NULL; } } static const HB_GC_FUNCS s_gcFILEFuncs = { FILE_release, hb_gcDummyMark }; static void hb_FILE_ret( FILE * p ) { if( p ) { void ** ph = ( void ** ) hb_gcAllocate( sizeof( FILE * ), &s_gcFILEFuncs ); *ph = p; hb_retptrGC( ph ); } else hb_retptr( NULL ); } static FILE * hb_FILE_par( int iParam ) { void ** ph = ( void ** ) hb_parptrGC( &s_gcFILEFuncs, iParam ); return ph ? ( FILE * ) *ph : NULL; } HB_FUNC( CURL_FOPEN ) { hb_FILE_ret( hb_fopen( hb_parcx( 1 ), "w+b" ) ); } HB_FUNC( CURL_EASY_SETOPT2 ) { if( PHB_CURL_is( 1 ) && HB_ISNUM( 2 ) ) { PHB_CURL hb_curl = PHB_CURL_par( 1 ); CURLcode res = ( CURLcode ) HB_CURLE_ERROR; if( hb_curl && ( hb_parni( 2 ) == HB_CURLOPT_STDERR ) ) { res = curl_easy_setopt( hb_curl->curl, CURLOPT_STDERR, hb_FILE_par( 3 ) ); } hb_retnl( ( long ) res ); } else hb_errRT_BASE( EG_ARG, 2010, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } [/pre2]

Петр: Здесь я использовал фрагменты кода из hbpgsql и hbcurl. Это нормально Добавил curl_easy_setopt2, хотя можно и curl_easy_setopt поправить. Использование: [pre2] LOCAL lVerbose := .T. LOCAL fStdErr := curl_fopen('verb.txt') ... ? curl_easy_setopt( curl, HB_CURLOPT_VERBOSE, lVerbose ) ? curl_easy_setopt2( curl, HB_CURLOPT_STDERR, fStdErr ) [/pre2]

Петр: Dima пишет: С DelayLoad хорошее решение Но такой фичи похоже нет в MINGW , что печально. Пока лучше с этим не связываться, геморно.

Dima: Петр пишет: Или самому написать что-то такое Спасибо , только не понятно куда этот кусок кода вставить , в сырец HBCURL и пересобрать ? Петр пишет: Пока лучше с этим не связыватся, геморно. Я уже смирился с этим

Петр: Dima пишет: Спасибо , только не понятно куда этот кусок кода вставить , в сырец HBCURL и пересобрать ? Да, добавить в hbcurl\core.c и пересобрать. В конец файла или я вот у себя добавил перед таким фрагментом /* Harbour interface */ /* ----------------- */

Dima: Петр пишет: Да, добавить в hbcurl\core.c и пересобрать. Да это работает , спасибо

Dima: Dima пишет: * если LIST средствами CURL получать через HB_CURLOPT_DIRLISTONLY * там только имена Был не прав и там еще 1 параметр и если он равен 0 тогда идет полный лист с размерами файлов и тд Но к сожалению свою маску задать не получится и там всегда *.* Поэтому юзаем HB_CURLOPT_CUSTOMREQUEST,"LIST "............



полная версия страницы