DisplayResults.class.php 222 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Hold the PMA_DisplayResults class
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. if (! defined('PHPMYADMIN')) {
  9. exit;
  10. }
  11. /**
  12. * Handle all the functionalities related to displaying results
  13. * of sql queries, stored procedure, browsing sql processes or
  14. * displaying binary log.
  15. *
  16. * @package PhpMyAdmin
  17. */
  18. class PMA_DisplayResults
  19. {
  20. // Define constants
  21. const NO_EDIT_OR_DELETE = 'nn';
  22. const UPDATE_ROW = 'ur';
  23. const DELETE_ROW = 'dr';
  24. const KILL_PROCESS = 'kp';
  25. const POSITION_LEFT = 'left';
  26. const POSITION_RIGHT = 'right';
  27. const POSITION_BOTH = 'both';
  28. const POSITION_NONE = 'none';
  29. const PLACE_TOP_DIRECTION_DROPDOWN = 'top_direction_dropdown';
  30. const PLACE_BOTTOM_DIRECTION_DROPDOWN = 'bottom_direction_dropdown';
  31. const DISP_DIR_HORIZONTAL = 'horizontal';
  32. const DISP_DIR_HORIZONTAL_FLIPPED = 'horizontalflipped';
  33. const DISP_DIR_VERTICAL = 'vertical';
  34. const DISPLAY_FULL_TEXT = 'F';
  35. const DISPLAY_PARTIAL_TEXT = 'P';
  36. const HEADER_FLIP_TYPE_AUTO = 'auto';
  37. const HEADER_FLIP_TYPE_CSS = 'css';
  38. const HEADER_FLIP_TYPE_FAKE = 'fake';
  39. const DATE_FIELD = 'date';
  40. const DATETIME_FIELD = 'datetime';
  41. const TIMESTAMP_FIELD = 'timestamp';
  42. const TIME_FIELD = 'time';
  43. const STRING_FIELD = 'string';
  44. const GEOMETRY_FIELD = 'geometry';
  45. const BLOB_FIELD = 'BLOB';
  46. const BINARY_FIELD = 'BINARY';
  47. const RELATIONAL_KEY = 'K';
  48. const RELATIONAL_DISPLAY_COLUMN = 'D';
  49. const GEOMETRY_DISP_GEOM = 'GEOM';
  50. const GEOMETRY_DISP_WKT = 'WKT';
  51. const GEOMETRY_DISP_WKB = 'WKB';
  52. const SMART_SORT_ORDER = 'SMART';
  53. const ASCENDING_SORT_DIR = 'ASC';
  54. const DESCENDING_SORT_DIR = 'DESC';
  55. const TABLE_TYPE_INNO_DB = 'InnoDB';
  56. const ALL_ROWS = 'all';
  57. const QUERY_TYPE_SELECT = 'SELECT';
  58. const ROUTINE_PROCEDURE = 'procedure';
  59. const ROUTINE_FUNCTION = 'function';
  60. const ACTION_LINK_CONTENT_ICONS = 'icons';
  61. const ACTION_LINK_CONTENT_TEXT = 'text';
  62. // Declare global fields
  63. /** array with properties of the class */
  64. private $_property_array = array(
  65. /** string Database name */
  66. 'db' => null,
  67. /** string Table name */
  68. 'table' => null,
  69. /** string the URL to go back in case of errors */
  70. 'goto' => null,
  71. /** string the SQL query */
  72. 'sql_query' => null,
  73. /**
  74. * integer the total number of rows returned by the SQL query without any
  75. * appended "LIMIT" clause programmatically
  76. */
  77. 'unlim_num_rows' => null,
  78. /** array meta information about fields */
  79. 'fields_meta' => null,
  80. /** boolean */
  81. 'is_count' => null,
  82. /** integer */
  83. 'is_export' => null,
  84. /** boolean */
  85. 'is_func' => null,
  86. /** integer */
  87. 'is_analyse' => null,
  88. /** integer the total number of rows returned by the SQL query */
  89. 'num_rows' => null,
  90. /** integer the total number of fields returned by the SQL query */
  91. 'fields_cnt' => null,
  92. /** double time taken for execute the SQL query */
  93. 'querytime' => null,
  94. /** string path for theme images directory */
  95. 'pma_theme_image' => null,
  96. /** string */
  97. 'text_dir' => null,
  98. /** boolean */
  99. 'is_maint' => null,
  100. /** boolean */
  101. 'is_explain' => null,
  102. /** boolean */
  103. 'is_show' => null,
  104. /** array table definitions */
  105. 'showtable' => null,
  106. /** string */
  107. 'printview' => null,
  108. /** string URL query */
  109. 'url_query' => null,
  110. /** array column names to highlight */
  111. 'highlight_columns' => null,
  112. /** array informations used with vertical display mode */
  113. 'vertical_display' => null,
  114. /** array mime types information of fields */
  115. 'mime_map' => null,
  116. /** boolean */
  117. 'editable' => null
  118. );
  119. /**
  120. * This variable contains the column transformation information
  121. * for some of the system databases.
  122. * One element of this array represent all relevant columns in all tables in
  123. * one specific database
  124. */
  125. public $transformation_info;
  126. /**
  127. * Get any property of this class
  128. *
  129. * @param string $property name of the property
  130. *
  131. * @return mixed|void if property exist, value of the relevant property
  132. */
  133. public function __get($property)
  134. {
  135. if (array_key_exists($property, $this->_property_array)) {
  136. return $this->_property_array[$property];
  137. }
  138. }
  139. /**
  140. * Set values for any property of this class
  141. *
  142. * @param string $property name of the property
  143. * @param mixed $value value to set
  144. *
  145. * @return void
  146. */
  147. public function __set($property, $value)
  148. {
  149. if (array_key_exists($property, $this->_property_array)) {
  150. $this->_property_array[$property] = $value;
  151. }
  152. }
  153. /**
  154. * Constructor for PMA_DisplayResults class
  155. *
  156. * @param string $db the database name
  157. * @param string $table the table name
  158. * @param string $goto the URL to go back in case of errors
  159. * @param string $sql_query the SQL query
  160. *
  161. * @access public
  162. */
  163. public function __construct($db, $table, $goto, $sql_query)
  164. {
  165. $this->_setDefaultTransformations();
  166. $this->__set('db', $db);
  167. $this->__set('table', $table);
  168. $this->__set('goto', $goto);
  169. $this->__set('sql_query', $sql_query);
  170. }
  171. /**
  172. * Sets default transformations for some columns
  173. *
  174. * @return void
  175. */
  176. private function _setDefaultTransformations()
  177. {
  178. $sql_highlighting_data = array(
  179. 'libraries/plugins/transformations/Text_Plain_Formatted.class.php',
  180. 'Text_Plain_Formatted',
  181. 'Text_Plain'
  182. );
  183. $this->transformation_info = array(
  184. 'information_schema' => array(
  185. 'events' => array(
  186. 'event_definition' => $sql_highlighting_data
  187. ),
  188. 'processlist' => array(
  189. 'info' => $sql_highlighting_data
  190. ),
  191. 'routines' => array(
  192. 'routine_definition' => $sql_highlighting_data
  193. ),
  194. 'triggers' => array(
  195. 'action_statement' => $sql_highlighting_data
  196. ),
  197. 'views' => array(
  198. 'view_definition' => $sql_highlighting_data
  199. )
  200. )
  201. );
  202. $cfgRelation = PMA_getRelationsParam();
  203. if ($cfgRelation['db']) {
  204. $this->transformation_info[$cfgRelation['db']] = array();
  205. $relDb = &$this->transformation_info[$cfgRelation['db']];
  206. if (! empty($cfgRelation['history'])) {
  207. $relDb[$cfgRelation['history']] = array(
  208. 'sqlquery' => $sql_highlighting_data
  209. );
  210. }
  211. if (! empty($cfgRelation['bookmark'])) {
  212. $relDb[$cfgRelation['bookmark']] = array(
  213. 'query' => $sql_highlighting_data
  214. );
  215. }
  216. if (! empty($cfgRelation['tracking'])) {
  217. $relDb[$cfgRelation['tracking']] = array(
  218. 'schema_sql' => $sql_highlighting_data,
  219. 'data_sql' => $sql_highlighting_data
  220. );
  221. }
  222. }
  223. }
  224. /**
  225. * Set properties which were not initialized at the constructor
  226. *
  227. * @param integer $unlim_num_rows the total number of rows returned by
  228. * the SQL query without any appended
  229. * "LIMIT" clause programmatically
  230. * @param array $fields_meta meta information about fields
  231. * @param boolean $is_count statement is SELECT COUNT
  232. * @param integer $is_export statement contains INTO OUTFILE
  233. * @param boolean $is_func statement contains a function like SUM()
  234. * @param integer $is_analyse statement contains PROCEDURE ANALYSE
  235. * @param integer $num_rows total no. of rows returned by SQL query
  236. * @param integer $fields_cnt total no.of fields returned by SQL query
  237. * @param double $querytime time taken for execute the SQL query
  238. * @param string $pmaThemeImage path for theme images directory
  239. * @param string $text_dir text direction
  240. * @param boolean $is_maint statement contains a maintenance command
  241. * @param boolean $is_explain statement contains EXPLAIN
  242. * @param boolean $is_show statement contains SHOW
  243. * @param array $showtable table definitions
  244. * @param string $printview print view was requested
  245. * @param string $url_query URL query
  246. * @param boolean $editable whether the results set is editable
  247. *
  248. * @return void
  249. *
  250. * @see sql.php
  251. */
  252. public function setProperties(
  253. $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func,
  254. $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir,
  255. $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query,
  256. $editable
  257. ) {
  258. $this->__set('unlim_num_rows', $unlim_num_rows);
  259. $this->__set('fields_meta', $fields_meta);
  260. $this->__set('is_count', $is_count);
  261. $this->__set('is_export', $is_export);
  262. $this->__set('is_func', $is_func);
  263. $this->__set('is_analyse', $is_analyse);
  264. $this->__set('num_rows', $num_rows);
  265. $this->__set('fields_cnt', $fields_cnt);
  266. $this->__set('querytime', $querytime);
  267. $this->__set('pma_theme_image', $pmaThemeImage);
  268. $this->__set('text_dir', $text_dir);
  269. $this->__set('is_maint', $is_maint);
  270. $this->__set('is_explain', $is_explain);
  271. $this->__set('is_show', $is_show);
  272. $this->__set('showtable', $showtable);
  273. $this->__set('printview', $printview);
  274. $this->__set('url_query', $url_query);
  275. $this->__set('editable', $editable);
  276. } // end of the 'setProperties()' function
  277. /**
  278. * Defines the display mode to use for the results of a SQL query
  279. *
  280. * It uses a synthetic string that contains all the required informations.
  281. * In this string:
  282. * - the first two characters stand for the action to do while
  283. * clicking on the "edit" link (e.g. 'ur' for update a row, 'nn' for no
  284. * edit link...);
  285. * - the next two characters stand for the action to do while
  286. * clicking on the "delete" link (e.g. 'kp' for kill a process, 'nn' for
  287. * no delete link...);
  288. * - the next characters are boolean values (1/0) and respectively stand
  289. * for sorting links, navigation bar, "insert a new row" link, the
  290. * bookmark feature, the expand/collapse text/blob fields button and
  291. * the "display printable view" option.
  292. * Of course '0'/'1' means the feature won't/will be enabled.
  293. *
  294. * @param string &$the_disp_mode the synthetic value for display_mode (see a few
  295. * lines above for explanations)
  296. * @param integer &$the_total the total number of rows returned by the SQL
  297. * query without any programmatically appended
  298. * LIMIT clause
  299. * (just a copy of $unlim_num_rows if it exists,
  300. * elsecomputed inside this function)
  301. *
  302. * @return array an array with explicit indexes for all the display
  303. * elements
  304. *
  305. * @access private
  306. *
  307. * @see getTable()
  308. */
  309. private function _setDisplayMode(&$the_disp_mode, &$the_total)
  310. {
  311. // Following variables are needed for use in isset/empty or
  312. // use with array indexes or safe use in foreach
  313. $db = $this->__get('db');
  314. $table = $this->__get('table');
  315. $unlim_num_rows = $this->__get('unlim_num_rows');
  316. $fields_meta = $this->__get('fields_meta');
  317. $printview = $this->__get('printview');
  318. // 1. Initializes the $do_display array
  319. $do_display = array();
  320. $do_display['edit_lnk'] = $the_disp_mode[0] . $the_disp_mode[1];
  321. $do_display['del_lnk'] = $the_disp_mode[2] . $the_disp_mode[3];
  322. $do_display['sort_lnk'] = (string) $the_disp_mode[4];
  323. $do_display['nav_bar'] = (string) $the_disp_mode[5];
  324. $do_display['ins_row'] = (string) $the_disp_mode[6];
  325. $do_display['bkm_form'] = (string) $the_disp_mode[7];
  326. $do_display['text_btn'] = (string) $the_disp_mode[8];
  327. $do_display['pview_lnk'] = (string) $the_disp_mode[9];
  328. // 2. Display mode is not "false for all elements" -> updates the
  329. // display mode
  330. if ($the_disp_mode != 'nnnn000000') {
  331. if (isset($printview) && ($printview == '1')) {
  332. // 2.0 Print view -> set all elements to false!
  333. $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link
  334. $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link
  335. $do_display['sort_lnk'] = (string) '0';
  336. $do_display['nav_bar'] = (string) '0';
  337. $do_display['ins_row'] = (string) '0';
  338. $do_display['bkm_form'] = (string) '0';
  339. $do_display['text_btn'] = (string) '0';
  340. $do_display['pview_lnk'] = (string) '0';
  341. } elseif ($this->__get('is_count') || $this->__get('is_analyse')
  342. || $this->__get('is_maint') || $this->__get('is_explain')
  343. ) {
  344. // 2.1 Statement is a "SELECT COUNT", a
  345. // "CHECK/ANALYZE/REPAIR/OPTIMIZE", an "EXPLAIN" one or
  346. // contains a "PROC ANALYSE" part
  347. $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link
  348. $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link
  349. $do_display['sort_lnk'] = (string) '0';
  350. $do_display['nav_bar'] = (string) '0';
  351. $do_display['ins_row'] = (string) '0';
  352. $do_display['bkm_form'] = (string) '1';
  353. if ($this->__get('is_maint')) {
  354. $do_display['text_btn'] = (string) '1';
  355. } else {
  356. $do_display['text_btn'] = (string) '0';
  357. }
  358. $do_display['pview_lnk'] = (string) '1';
  359. } elseif ($this->__get('is_show')) {
  360. // 2.2 Statement is a "SHOW..."
  361. /**
  362. * 2.2.1
  363. * @todo defines edit/delete links depending on show statement
  364. */
  365. preg_match(
  366. '@^SHOW[[:space:]]+(VARIABLES|(FULL[[:space:]]+)?'
  367. . 'PROCESSLIST|STATUS|TABLE|GRANTS|CREATE|LOGS|DATABASES|FIELDS'
  368. . ')@i',
  369. $this->__get('sql_query'), $which
  370. );
  371. if (isset($which[1])
  372. && (strpos(' ' . strtoupper($which[1]), 'PROCESSLIST') > 0)
  373. ) {
  374. // no edit link
  375. $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE;
  376. // "kill process" type edit link
  377. $do_display['del_lnk'] = self::KILL_PROCESS;
  378. } else {
  379. // Default case -> no links
  380. // no edit link
  381. $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE;
  382. // no delete link
  383. $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE;
  384. }
  385. // 2.2.2 Other settings
  386. $do_display['sort_lnk'] = (string) '0';
  387. $do_display['nav_bar'] = (string) '0';
  388. $do_display['ins_row'] = (string) '0';
  389. $do_display['bkm_form'] = (string) '1';
  390. $do_display['text_btn'] = (string) '1';
  391. $do_display['pview_lnk'] = (string) '1';
  392. } else {
  393. // 2.3 Other statements (ie "SELECT" ones) -> updates
  394. // $do_display['edit_lnk'], $do_display['del_lnk'] and
  395. // $do_display['text_btn'] (keeps other default values)
  396. $prev_table = $fields_meta[0]->table;
  397. $do_display['text_btn'] = (string) '1';
  398. for ($i = 0; $i < $this->__get('fields_cnt'); $i++) {
  399. $is_link = ($do_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  400. || ($do_display['del_lnk'] != self::NO_EDIT_OR_DELETE)
  401. || ($do_display['sort_lnk'] != '0')
  402. || ($do_display['ins_row'] != '0');
  403. // 2.3.2 Displays edit/delete/sort/insert links?
  404. if ($is_link
  405. && (($fields_meta[$i]->table == '')
  406. || ($fields_meta[$i]->table != $prev_table))
  407. ) {
  408. // don't display links
  409. $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE;
  410. $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE;
  411. /**
  412. * @todo May be problematic with same field names
  413. * in two joined table.
  414. */
  415. // $do_display['sort_lnk'] = (string) '0';
  416. $do_display['ins_row'] = (string) '0';
  417. if ($do_display['text_btn'] == '1') {
  418. break;
  419. }
  420. } // end if (2.3.2)
  421. // 2.3.3 Always display print view link
  422. $do_display['pview_lnk'] = (string) '1';
  423. $prev_table = $fields_meta[$i]->table;
  424. } // end for
  425. } // end if..elseif...else (2.1 -> 2.3)
  426. } // end if (2)
  427. // 3. Gets the total number of rows if it is unknown
  428. if (isset($unlim_num_rows) && $unlim_num_rows != '') {
  429. $the_total = $unlim_num_rows;
  430. } elseif ((($do_display['nav_bar'] == '1')
  431. || ($do_display['sort_lnk'] == '1'))
  432. && (strlen($db) && !empty($table))
  433. ) {
  434. $the_total = PMA_Table::countRecords($db, $table);
  435. }
  436. // 4. If navigation bar or sorting fields names URLs should be
  437. // displayed but there is only one row, change these settings to
  438. // false
  439. if ($do_display['nav_bar'] == '1' || $do_display['sort_lnk'] == '1') {
  440. // - Do not display sort links if less than 2 rows.
  441. // - For a VIEW we (probably) did not count the number of rows
  442. // so don't test this number here, it would remove the possibility
  443. // of sorting VIEW results.
  444. if (isset($unlim_num_rows)
  445. && ($unlim_num_rows < 2)
  446. && ! PMA_Table::isView($db, $table)
  447. ) {
  448. // force display of navbar for vertical/horizontal display-choice.
  449. // $do_display['nav_bar'] = (string) '0';
  450. $do_display['sort_lnk'] = (string) '0';
  451. }
  452. } // end if (3)
  453. // 5. Updates the synthetic var
  454. $the_disp_mode = join('', $do_display);
  455. return $do_display;
  456. } // end of the 'setDisplayMode()' function
  457. /**
  458. * Return true if we are executing a query in the form of
  459. * "SELECT * FROM <a table> ..."
  460. *
  461. * @param array $analyzed_sql the analyzed query
  462. *
  463. * @return boolean
  464. *
  465. * @access private
  466. *
  467. * @see _getTableHeaders(), _getColumnParams()
  468. */
  469. private function _isSelect($analyzed_sql)
  470. {
  471. if (!isset($analyzed_sql[0]['select_expr'])) {
  472. $analyzed_sql[0]['select_expr'] = 0;
  473. }
  474. return ! ($this->__get('is_count') || $this->__get('is_export')
  475. || $this->__get('is_func') || $this->__get('is_analyse'))
  476. && (count($analyzed_sql[0]['select_expr']) == 0)
  477. && isset($analyzed_sql[0]['queryflags']['select_from'])
  478. && (count($analyzed_sql[0]['table_ref']) == 1);
  479. }
  480. /**
  481. * Get a navigation button
  482. *
  483. * @param string $caption iconic caption for button
  484. * @param string $title text for button
  485. * @param integer $pos position for next query
  486. * @param string $html_sql_query query ready for display
  487. * @param string $onsubmit optional onsubmit clause
  488. * @param string $input_for_real_end optional hidden field for special treatment
  489. * @param string $onclick optional onclick clause
  490. *
  491. * @return string html content
  492. *
  493. * @access private
  494. *
  495. * @see _getMoveBackwardButtonsForTableNavigation(),
  496. * _getMoveForwardButtonsForTableNavigation()
  497. */
  498. private function _getTableNavigationButton(
  499. $caption, $title, $pos, $html_sql_query, $onsubmit = '',
  500. $input_for_real_end = '', $onclick = ''
  501. ) {
  502. $caption_output = '';
  503. if (PMA_Util::showIcons('TableNavigationLinksMode')) {
  504. $caption_output .= $caption;
  505. }
  506. if (PMA_Util::showText('TableNavigationLinksMode')) {
  507. $caption_output .= '&nbsp;' . $title;
  508. }
  509. $title_output = ' title="' . $title . '"';
  510. return '<td>'
  511. . '<form action="sql.php" method="post" ' . $onsubmit . '>'
  512. . PMA_URL_getHiddenInputs(
  513. $this->__get('db'), $this->__get('table')
  514. )
  515. . '<input type="hidden" name="sql_query" value="'
  516. . $html_sql_query . '" />'
  517. . '<input type="hidden" name="pos" value="' . $pos . '" />'
  518. . '<input type="hidden" name="goto" value="' . $this->__get('goto')
  519. . '" />'
  520. . $input_for_real_end
  521. . '<input type="submit" name="navig"'
  522. . ' class="ajax" '
  523. . 'value="' . $caption_output . '" ' . $title_output . $onclick . ' />'
  524. . '</form>'
  525. . '</td>';
  526. } // end function _getTableNavigationButton()
  527. /**
  528. * Get a navigation bar to browse among the results of a SQL query
  529. *
  530. * @param integer $pos_next the offset for the "next" page
  531. * @param integer $pos_prev the offset for the "previous" page
  532. * @param string $id_for_direction_dropdown the id for the direction dropdown
  533. * @param boolean $is_innodb whether its InnoDB or not
  534. *
  535. * @return string html content
  536. *
  537. * @access private
  538. *
  539. * @see _getTable()
  540. */
  541. private function _getTableNavigation(
  542. $pos_next, $pos_prev, $id_for_direction_dropdown, $is_innodb
  543. ) {
  544. $table_navigation_html = '';
  545. $showtable = $this->__get('showtable'); // To use in isset
  546. // here, using htmlentities() would cause problems if the query
  547. // contains accented characters
  548. $html_sql_query = htmlspecialchars($this->__get('sql_query'));
  549. /**
  550. * @todo move this to a central place
  551. * @todo for other future table types
  552. */
  553. $is_innodb = (isset($showtable['Type'])
  554. && $showtable['Type'] == self::TABLE_TYPE_INNO_DB);
  555. // Navigation bar
  556. $table_navigation_html .= '<table class="navigation nospacing nopadding">'
  557. . '<tr>'
  558. . '<td class="navigation_separator"></td>';
  559. // Move to the beginning or to the previous page
  560. if ($_SESSION['tmpval']['pos']
  561. && ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS)
  562. ) {
  563. $table_navigation_html
  564. .= $this->_getMoveBackwardButtonsForTableNavigation(
  565. $html_sql_query, $pos_prev
  566. );
  567. } // end move back
  568. $nbTotalPage = 1;
  569. //page redirection
  570. // (unless we are showing all records)
  571. if ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS) { //if1
  572. $pageNow = @floor(
  573. $_SESSION['tmpval']['pos']
  574. / $_SESSION['tmpval']['max_rows']
  575. ) + 1;
  576. $nbTotalPage = @ceil(
  577. $this->__get('unlim_num_rows')
  578. / $_SESSION['tmpval']['max_rows']
  579. );
  580. if ($nbTotalPage > 1) { //if2
  581. $table_navigation_html .= '<td>';
  582. $_url_params = array(
  583. 'db' => $this->__get('db'),
  584. 'table' => $this->__get('table'),
  585. 'sql_query' => $this->__get('sql_query'),
  586. 'goto' => $this->__get('goto'),
  587. );
  588. //<form> to keep the form alignment of button < and <<
  589. // and also to know what to execute when the selector changes
  590. $table_navigation_html .= '<form action="sql.php'
  591. . PMA_URL_getCommon($_url_params)
  592. . '" method="post">';
  593. $table_navigation_html .= PMA_Util::pageselector(
  594. 'pos',
  595. $_SESSION['tmpval']['max_rows'],
  596. $pageNow, $nbTotalPage, 200, 5, 5, 20, 10
  597. );
  598. $table_navigation_html .= '</form>'
  599. . '</td>';
  600. } //_if2
  601. } //_if1
  602. // Display the "Show all" button if allowed
  603. if (($this->__get('num_rows') < $this->__get('unlim_num_rows'))
  604. && ($GLOBALS['cfg']['ShowAll']
  605. || ($this->__get('unlim_num_rows') <= 500))
  606. ) {
  607. $table_navigation_html .= $this->_getShowAllButtonForTableNavigation(
  608. $html_sql_query
  609. );
  610. } // end show all
  611. // Move to the next page or to the last one
  612. $endpos = $_SESSION['tmpval']['pos']
  613. + $_SESSION['tmpval']['max_rows'];
  614. if (($endpos < $this->__get('unlim_num_rows'))
  615. && ($this->__get('num_rows') >= $_SESSION['tmpval']['max_rows'])
  616. && ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS)
  617. ) {
  618. $table_navigation_html
  619. .= $this->_getMoveForwardButtonsForTableNavigation(
  620. $html_sql_query, $pos_next, $is_innodb
  621. );
  622. } // end move toward
  623. // show separator if pagination happen
  624. if ($nbTotalPage > 1) {
  625. $table_navigation_html
  626. .= '<td><div class="navigation_separator">|</div></td>';
  627. }
  628. $table_navigation_html .= '<td>'
  629. . '<div class="save_edited hide">'
  630. . '<input type="submit" value="' . __('Save edited data') . '" />'
  631. . '<div class="navigation_separator">|</div>'
  632. . '</div>'
  633. . '</td>'
  634. . '<td>'
  635. . '<div class="restore_column hide">'
  636. . '<input type="submit" value="' . __('Restore column order') . '" />'
  637. . '<div class="navigation_separator">|</div>'
  638. . '</div>'
  639. . '</td>';
  640. // if displaying a VIEW, $unlim_num_rows could be zero because
  641. // of $cfg['MaxExactCountViews']; in this case, avoid passing
  642. // the 5th parameter to checkFormElementInRange()
  643. // (this means we can't validate the upper limit
  644. $table_navigation_html .= '<td class="navigation_goto">';
  645. $table_navigation_html .= '<form action="sql.php" method="post" '
  646. . 'onsubmit="return '
  647. . '(checkFormElementInRange('
  648. . 'this, '
  649. . '\'session_max_rows\', '
  650. . '\''
  651. . str_replace('\'', '\\\'', __('%d is not valid row number.'))
  652. . '\', '
  653. . '1)'
  654. . ' &amp;&amp; '
  655. . 'checkFormElementInRange('
  656. . 'this, '
  657. . '\'pos\', '
  658. . '\''
  659. . str_replace('\'', '\\\'', __('%d is not valid row number.'))
  660. . '\', '
  661. . '0'
  662. . (($this->__get('unlim_num_rows') > 0)
  663. ? ', ' . ($this->__get('unlim_num_rows') - 1)
  664. : ''
  665. )
  666. . ')'
  667. . ')'
  668. . '">';
  669. $table_navigation_html .= PMA_URL_getHiddenInputs(
  670. $this->__get('db'), $this->__get('table')
  671. );
  672. $table_navigation_html .= $this->_getAdditionalFieldsForTableNavigation(
  673. $html_sql_query, $id_for_direction_dropdown
  674. );
  675. $table_navigation_html .= '</form>'
  676. . '</td>'
  677. . '<td class="navigation_separator"></td>'
  678. . '<td>'
  679. . '<span>' . __('Filter rows') . ':</span>'
  680. . '<input type="text" class="filter_rows" placeholder="'
  681. . __('Search this table') . '">'
  682. . '</td>'
  683. . '<td class="navigation_separator"></td>'
  684. . '</tr>'
  685. . '</table>';
  686. return $table_navigation_html;
  687. } // end of the '_getTableNavigation()' function
  688. /**
  689. * Prepare move backward buttons - previous and first
  690. *
  691. * @param string $html_sql_query the sql encoded by html special characters
  692. * @param integer $pos_prev the offset for the "previous" page
  693. *
  694. * @return string html content
  695. *
  696. * @access private
  697. *
  698. * @see _getTableNavigation()
  699. */
  700. private function _getMoveBackwardButtonsForTableNavigation(
  701. $html_sql_query, $pos_prev
  702. ) {
  703. return $this->_getTableNavigationButton(
  704. '&lt;&lt;', _pgettext('First page', 'Begin'), 0, $html_sql_query
  705. )
  706. . $this->_getTableNavigationButton(
  707. '&lt;', _pgettext('Previous page', 'Previous'), $pos_prev,
  708. $html_sql_query
  709. );
  710. } // end of the '_getMoveBackwardButtonsForTableNavigation()' function
  711. /**
  712. * Prepare Show All button for table navigation
  713. *
  714. * @param string $html_sql_query the sql encoded by html special characters
  715. *
  716. * @return string html content
  717. *
  718. * @access private
  719. *
  720. * @see _getTableNavigation()
  721. */
  722. private function _getShowAllButtonForTableNavigation($html_sql_query)
  723. {
  724. return "\n"
  725. . '<td>'
  726. . '<form action="sql.php" method="post">'
  727. . PMA_URL_getHiddenInputs(
  728. $this->__get('db'), $this->__get('table')
  729. )
  730. . '<input type="hidden" name="sql_query" value="'
  731. . $html_sql_query . '" />'
  732. . '<input type="hidden" name="pos" value="0" />'
  733. . '<input type="hidden" name="session_max_rows" value="all" />'
  734. . '<input type="hidden" name="goto" value="' . $this->__get('goto')
  735. . '" />'
  736. . '<input type="submit" name="navig" value="' . __('Show all') . '" />'
  737. . '</form>'
  738. . '</td>';
  739. } // end of the '_getShowAllButtonForTableNavigation()' function
  740. /**
  741. * Prepare move forward buttons - next and last
  742. *
  743. * @param string $html_sql_query the sql encoded by htmlspecialchars()
  744. * @param integer $pos_next the offset for the "next" page
  745. * @param boolean $is_innodb whether it's InnoDB or not
  746. *
  747. * @return string $buttons_html html content
  748. *
  749. * @access private
  750. *
  751. * @see _getTableNavigation()
  752. */
  753. private function _getMoveForwardButtonsForTableNavigation(
  754. $html_sql_query, $pos_next, $is_innodb
  755. ) {
  756. // display the Next button
  757. $buttons_html = $this->_getTableNavigationButton(
  758. '&gt;',
  759. _pgettext('Next page', 'Next'),
  760. $pos_next,
  761. $html_sql_query
  762. );
  763. // prepare some options for the End button
  764. if ($is_innodb
  765. && $this->__get('unlim_num_rows') > $GLOBALS['cfg']['MaxExactCount']
  766. ) {
  767. $input_for_real_end = '<input id="real_end_input" type="hidden" '
  768. . 'name="find_real_end" value="1" />';
  769. // no backquote around this message
  770. $onclick = '';
  771. } else {
  772. $input_for_real_end = $onclick = '';
  773. }
  774. $maxRows = $_SESSION['tmpval']['max_rows'];
  775. $onsubmit = 'onsubmit="return '
  776. . ($_SESSION['tmpval']['pos']
  777. + $maxRows
  778. < $this->__get('unlim_num_rows')
  779. && $this->__get('num_rows') >= $maxRows)
  780. ? 'true'
  781. : 'false' . '"';
  782. // display the End button
  783. $buttons_html .= $this->_getTableNavigationButton(
  784. '&gt;&gt;',
  785. _pgettext('Last page', 'End'),
  786. @((ceil(
  787. $this->__get('unlim_num_rows')
  788. / $_SESSION['tmpval']['max_rows']
  789. )- 1) * $maxRows),
  790. $html_sql_query, $onsubmit, $input_for_real_end, $onclick
  791. );
  792. return $buttons_html;
  793. } // end of the '_getMoveForwardButtonsForTableNavigation()' function
  794. /**
  795. * Prepare fields for table navigation
  796. * Number of rows
  797. *
  798. * @param string $html_sql_query the sql encoded by htmlspecialchars()
  799. * @param string $id_for_direction_dropdown the id for the direction dropdown
  800. *
  801. * @return string $additional_fields_html html content
  802. *
  803. * @access private
  804. *
  805. * @see _getTableNavigation()
  806. */
  807. private function _getAdditionalFieldsForTableNavigation(
  808. $html_sql_query, $id_for_direction_dropdown
  809. ) {
  810. $additional_fields_html = '';
  811. $additional_fields_html .= '<input type="hidden" name="sql_query" '
  812. . 'value="' . $html_sql_query . '" />'
  813. . '<input type="hidden" name="goto" value="' . $this->__get('goto')
  814. . '" />'
  815. . '<input type="hidden" name="pos" size="3" value="'
  816. // Do not change the position when changing the number of rows
  817. . $_SESSION['tmpval']['pos'] . '" />';
  818. $numberOfRowsChoices = array(
  819. '25' => 25,
  820. '50' => 50,
  821. '100' => 100,
  822. '250' => 250,
  823. '500' => 500
  824. );
  825. $additional_fields_html .= __('Number of rows:') . ' ';
  826. $additional_fields_html .= PMA_Util::getDropdown(
  827. 'session_max_rows', $numberOfRowsChoices,
  828. $_SESSION['tmpval']['max_rows'], '', 'autosubmit'
  829. );
  830. if ($GLOBALS['cfg']['ShowDisplayDirection']) {
  831. // Display mode (horizontal/vertical)
  832. $additional_fields_html .= __('Mode:') . ' ' . "\n";
  833. $choices = array(
  834. 'horizontal' => __('horizontal'),
  835. 'horizontalflipped' => __('horizontal (rotated headers)'),
  836. 'vertical' => __('vertical')
  837. );
  838. $additional_fields_html .= PMA_Util::getDropdown(
  839. 'disp_direction', $choices,
  840. $_SESSION['tmpval']['disp_direction'],
  841. $id_for_direction_dropdown, 'autosubmit'
  842. );
  843. unset($choices);
  844. }
  845. return $additional_fields_html;
  846. } // end of the '_getAdditionalFieldsForTableNavigation()' function
  847. /**
  848. * Get the headers of the results table
  849. *
  850. * @param array &$is_display which elements to display
  851. * @param array|string $analyzed_sql the analyzed query
  852. * @param array $sort_expression sort expression
  853. * @param array $sort_expression_nodirection sort expression
  854. * without direction
  855. * @param array $sort_direction sort direction
  856. * @param boolean $is_limited_display with limited operations
  857. * or not
  858. *
  859. * @return string html content
  860. *
  861. * @access private
  862. *
  863. * @see getTable()
  864. */
  865. private function _getTableHeaders(
  866. &$is_display, $analyzed_sql = '',
  867. $sort_expression = '', $sort_expression_nodirection = '',
  868. $sort_direction = '', $is_limited_display = false
  869. ) {
  870. $table_headers_html = '';
  871. // Following variable are needed for use in isset/empty or
  872. // use with array indexes/safe use in foreach
  873. $fields_meta = $this->__get('fields_meta');
  874. $highlight_columns = $this->__get('highlight_columns');
  875. $printview = $this->__get('printview');
  876. $vertical_display = $this->__get('vertical_display');
  877. // required to generate sort links that will remember whether the
  878. // "Show all" button has been clicked
  879. $sql_md5 = md5($this->__get('sql_query'));
  880. $session_max_rows = $is_limited_display
  881. ? 0
  882. : $_SESSION['tmpval']['query'][$sql_md5]['max_rows'];
  883. $direction = isset($_SESSION['tmpval']['disp_direction'])
  884. ? $_SESSION['tmpval']['disp_direction']
  885. : '';
  886. if ($analyzed_sql == '') {
  887. $analyzed_sql = array();
  888. }
  889. $directionCondition = ($direction == self::DISP_DIR_HORIZONTAL)
  890. || ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED);
  891. // can the result be sorted?
  892. if ($is_display['sort_lnk'] == '1') {
  893. list($unsorted_sql_query, $drop_down_html)
  894. = $this->_getUnsortedSqlAndSortByKeyDropDown(
  895. $analyzed_sql, $sort_expression
  896. );
  897. $table_headers_html .= $drop_down_html;
  898. }
  899. // Output data needed for grid editing
  900. $table_headers_html .= '<input id="save_cells_at_once" type="hidden" value="'
  901. . $GLOBALS['cfg']['SaveCellsAtOnce'] . '" />'
  902. . '<div class="common_hidden_inputs">'
  903. . PMA_URL_getHiddenInputs(
  904. $this->__get('db'), $this->__get('table')
  905. )
  906. . '</div>';
  907. // Output data needed for column reordering and show/hide column
  908. if ($this->_isSelect($analyzed_sql)) {
  909. $table_headers_html .= $this->_getDataForResettingColumnOrder();
  910. }
  911. $vertical_display['emptypre'] = 0;
  912. $vertical_display['emptyafter'] = 0;
  913. $vertical_display['textbtn'] = '';
  914. $full_or_partial_text_link = null;
  915. $this->__set('vertical_display', $vertical_display);
  916. // Display options (if we are not in print view)
  917. if (! (isset($printview) && ($printview == '1')) && ! $is_limited_display) {
  918. $table_headers_html .= $this->_getOptionsBlock();
  919. // prepare full/partial text button or link
  920. $full_or_partial_text_link = $this->_getFullOrPartialTextButtonOrLink();
  921. }
  922. // Start of form for multi-rows edit/delete/export
  923. $table_headers_html .= $this->_getFormForMultiRowOperations(
  924. $is_display['del_lnk']
  925. );
  926. // 1. Set $colspan or $rowspan and generate html with full/partial
  927. // text button or link
  928. list($colspan, $rowspan, $button_html)
  929. = $this->_getFieldVisibilityParams(
  930. $directionCondition, $is_display, $full_or_partial_text_link
  931. );
  932. $table_headers_html .= $button_html;
  933. // 2. Displays the fields' name
  934. // 2.0 If sorting links should be used, checks if the query is a "JOIN"
  935. // statement (see 2.1.3)
  936. // 2.0.1 Prepare Display column comments if enabled
  937. // ($GLOBALS['cfg']['ShowBrowseComments']).
  938. // Do not show comments, if using horizontalflipped mode,
  939. // because of space usage
  940. $comments_map = $this->_getTableCommentsArray($direction, $analyzed_sql);
  941. if ($GLOBALS['cfgRelation']['commwork']
  942. && $GLOBALS['cfgRelation']['mimework']
  943. && $GLOBALS['cfg']['BrowseMIME']
  944. && ! $_SESSION['tmpval']['hide_transformation']
  945. ) {
  946. include_once './libraries/transformations.lib.php';
  947. $this->__set(
  948. 'mime_map',
  949. PMA_getMIME($this->__get('db'), $this->__get('table'))
  950. );
  951. }
  952. // See if we have to highlight any header fields of a WHERE query.
  953. // Uses SQL-Parser results.
  954. $this->_setHighlightedColumnGlobalField($analyzed_sql);
  955. list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql);
  956. for ($j = 0; $j < $this->__get('fields_cnt'); $j++) {
  957. // assign $i with appropriate column order
  958. $i = $col_order ? $col_order[$j] : $j;
  959. // See if this column should get highlight because it's used in the
  960. // where-query.
  961. $condition_field = (isset($highlight_columns[$fields_meta[$i]->name])
  962. || isset(
  963. $highlight_columns[PMA_Util::backquote($fields_meta[$i]->name)])
  964. )
  965. ? true
  966. : false;
  967. // 2.0 Prepare comment-HTML-wrappers for each row, if defined/enabled.
  968. $comments = $this->_getCommentForRow($comments_map, $fields_meta[$i]);
  969. $vertical_display = $this->__get('vertical_display');
  970. if (($is_display['sort_lnk'] == '1') && ! $is_limited_display) {
  971. list($order_link, $sorted_header_html)
  972. = $this->_getOrderLinkAndSortedHeaderHtml(
  973. $fields_meta[$i], $sort_expression,
  974. $sort_expression_nodirection, $i, $unsorted_sql_query,
  975. $session_max_rows, $direction, $comments,
  976. $sort_direction, $directionCondition, $col_visib,
  977. $col_visib[$j]
  978. );
  979. $table_headers_html .= $sorted_header_html;
  980. $vertical_display['desc'][] = ' <th '
  981. . 'class="draggable'
  982. . ($condition_field ? ' condition' : '')
  983. . '" data-column="' . htmlspecialchars($fields_meta[$i]->name)
  984. . '">' . "\n" . $order_link . $comments . ' </th>' . "\n";
  985. } else {
  986. // 2.2 Results can't be sorted
  987. if ($directionCondition) {
  988. $table_headers_html
  989. .= $this->_getDraggableClassForNonSortableColumns(
  990. $col_visib, $col_visib[$j], $condition_field,
  991. $direction, $fields_meta[$i], $comments
  992. );
  993. }
  994. $vertical_display['desc'][] = ' <th '
  995. . 'class="draggable'
  996. . ($condition_field ? ' condition"' : '')
  997. . '" data-column="' . htmlspecialchars($fields_meta[$i]->name)
  998. . '">' . "\n" . ' '
  999. . htmlspecialchars($fields_meta[$i]->name)
  1000. . "\n" . $comments . ' </th>';
  1001. } // end else (2.2)
  1002. $this->__set('vertical_display', $vertical_display);
  1003. } // end for
  1004. // Display column at rightside - checkboxes or empty column
  1005. if (! $printview) {
  1006. $table_headers_html .= $this->_getColumnAtRightSide(
  1007. $is_display, $directionCondition, $full_or_partial_text_link,
  1008. $colspan, $rowspan
  1009. );
  1010. }
  1011. if ($directionCondition) {
  1012. $table_headers_html .= '</tr>'
  1013. . '</thead>';
  1014. }
  1015. return $table_headers_html;
  1016. } // end of the '_getTableHeaders()' function
  1017. /**
  1018. * Prepare unsorted sql query and sort by key drop down
  1019. *
  1020. * @param array $analyzed_sql the analyzed query
  1021. * @param string $sort_expression sort expression
  1022. *
  1023. * @return array two element array - $unsorted_sql_query, $drop_down_html
  1024. *
  1025. * @access private
  1026. *
  1027. * @see _getTableHeaders()
  1028. */
  1029. private function _getUnsortedSqlAndSortByKeyDropDown(
  1030. $analyzed_sql, $sort_expression
  1031. ) {
  1032. $drop_down_html = '';
  1033. // Just as fallback
  1034. $unsorted_sql_query = $this->__get('sql_query');
  1035. if (isset($analyzed_sql[0]['unsorted_query'])) {
  1036. $unsorted_sql_query = $analyzed_sql[0]['unsorted_query'];
  1037. }
  1038. // Handles the case of multiple clicks on a column's header
  1039. // which would add many spaces before "ORDER BY" in the
  1040. // generated query.
  1041. $unsorted_sql_query = trim($unsorted_sql_query);
  1042. // sorting by indexes, only if it makes sense (only one table ref)
  1043. if (isset($analyzed_sql)
  1044. && isset($analyzed_sql[0])
  1045. && isset($analyzed_sql[0]['querytype'])
  1046. && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT)
  1047. && isset($analyzed_sql[0]['table_ref'])
  1048. && (count($analyzed_sql[0]['table_ref']) == 1)
  1049. ) {
  1050. // grab indexes data:
  1051. $indexes = PMA_Index::getFromTable(
  1052. $this->__get('table'),
  1053. $this->__get('db')
  1054. );
  1055. // do we have any index?
  1056. if ($indexes) {
  1057. $drop_down_html = $this->_getSortByKeyDropDown(
  1058. $indexes, $sort_expression,
  1059. $unsorted_sql_query
  1060. );
  1061. }
  1062. }
  1063. return array($unsorted_sql_query, $drop_down_html);
  1064. } // end of the '_getUnsortedSqlAndSortByKeyDropDown()' function
  1065. /**
  1066. * Prepare sort by key dropdown - html code segment
  1067. *
  1068. * @param array $indexes the indexes of the table for sort criteria
  1069. * @param string $sort_expression the sort expression
  1070. * @param string $unsorted_sql_query the unsorted sql query
  1071. *
  1072. * @return string $drop_down_html html content
  1073. *
  1074. * @access private
  1075. *
  1076. * @see _getTableHeaders()
  1077. */
  1078. private function _getSortByKeyDropDown(
  1079. $indexes, $sort_expression, $unsorted_sql_query
  1080. ) {
  1081. $drop_down_html = '';
  1082. $drop_down_html .= '<form action="sql.php" method="post">' . "\n"
  1083. . PMA_URL_getHiddenInputs(
  1084. $this->__get('db'), $this->__get('table')
  1085. )
  1086. . __('Sort by key')
  1087. . ': <select name="sql_query" class="autosubmit">' . "\n";
  1088. $used_index = false;
  1089. $local_order = (isset($sort_expression) ? $sort_expression : '');
  1090. foreach ($indexes as $index) {
  1091. $asc_sort = '`'
  1092. . implode('` ASC, `', array_keys($index->getColumns()))
  1093. . '` ASC';
  1094. $desc_sort = '`'
  1095. . implode('` DESC, `', array_keys($index->getColumns()))
  1096. . '` DESC';
  1097. $used_index = $used_index
  1098. || ($local_order == $asc_sort)
  1099. || ($local_order == $desc_sort);
  1100. if (preg_match(
  1101. '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|'
  1102. . 'FOR UPDATE|LOCK IN SHARE MODE))@is',
  1103. $unsorted_sql_query, $my_reg
  1104. )) {
  1105. $unsorted_sql_query_first_part = $my_reg[1];
  1106. $unsorted_sql_query_second_part = $my_reg[2];
  1107. } else {
  1108. $unsorted_sql_query_first_part = $unsorted_sql_query;
  1109. $unsorted_sql_query_second_part = '';
  1110. }
  1111. $drop_down_html .= '<option value="'
  1112. . htmlspecialchars(
  1113. $unsorted_sql_query_first_part . "\n"
  1114. . ' ORDER BY ' . $asc_sort
  1115. . $unsorted_sql_query_second_part
  1116. )
  1117. . '"' . ($local_order == $asc_sort
  1118. ? ' selected="selected"'
  1119. : '')
  1120. . '>' . htmlspecialchars($index->getName()) . ' ('
  1121. . __('Ascending') . ')</option>';
  1122. $drop_down_html .= '<option value="'
  1123. . htmlspecialchars(
  1124. $unsorted_sql_query_first_part . "\n"
  1125. . ' ORDER BY ' . $desc_sort
  1126. . $unsorted_sql_query_second_part
  1127. )
  1128. . '"' . ($local_order == $desc_sort
  1129. ? ' selected="selected"'
  1130. : '')
  1131. . '>' . htmlspecialchars($index->getName()) . ' ('
  1132. . __('Descending') . ')</option>';
  1133. }
  1134. $drop_down_html .= '<option value="' . htmlspecialchars($unsorted_sql_query)
  1135. . '"' . ($used_index ? '' : ' selected="selected"') . '>' . __('None')
  1136. . '</option>'
  1137. . '</select>' . "\n"
  1138. . '</form>' . "\n";
  1139. return $drop_down_html;
  1140. } // end of the '_getSortByKeyDropDown()' function
  1141. /**
  1142. * Set column span, row span and prepare html with full/partial
  1143. * text button or link
  1144. *
  1145. * @param boolean $directionCondition display direction horizontal or
  1146. * horizontalflipped
  1147. * @param array &$is_display which elements to display
  1148. * @param string $full_or_partial_text_link full/partial link or text button
  1149. *
  1150. * @return array 3 element array - $colspan, $rowspan, $button_html
  1151. *
  1152. * @access private
  1153. *
  1154. * @see _getTableHeaders()
  1155. */
  1156. private function _getFieldVisibilityParams(
  1157. $directionCondition, &$is_display, $full_or_partial_text_link
  1158. ) {
  1159. $button_html = '';
  1160. $colspan = $rowspan = null;
  1161. $vertical_display = $this->__get('vertical_display');
  1162. // 1. Displays the full/partial text button (part 1)...
  1163. if ($directionCondition) {
  1164. $button_html .= '<thead><tr>' . "\n";
  1165. $colspan = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  1166. && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
  1167. ? ' colspan="4"'
  1168. : '';
  1169. } else {
  1170. $rowspan = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  1171. && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
  1172. ? ' rowspan="4"'
  1173. : '';
  1174. }
  1175. // ... before the result table
  1176. if ((($is_display['edit_lnk'] == self::NO_EDIT_OR_DELETE)
  1177. && ($is_display['del_lnk'] == self::NO_EDIT_OR_DELETE))
  1178. && ($is_display['text_btn'] == '1')
  1179. ) {
  1180. $vertical_display['emptypre']
  1181. = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  1182. && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
  1183. if ($directionCondition) {
  1184. $button_html .= '<th colspan="' . $this->__get('fields_cnt') . '">'
  1185. . '</th>'
  1186. . '</tr>'
  1187. . '<tr>';
  1188. // end horizontal/horizontalflipped mode
  1189. } else {
  1190. $span = $this->__get('num_rows') + 1 + floor(
  1191. $this->__get('num_rows')
  1192. / $_SESSION['tmpval']['repeat_cells']
  1193. );
  1194. $button_html .= '<tr><th colspan="' . $span . '"></th></tr>';
  1195. } // end vertical mode
  1196. } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
  1197. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  1198. && ($is_display['text_btn'] == '1')
  1199. ) {
  1200. // ... at the left column of the result table header if possible
  1201. // and required
  1202. $vertical_display['emptypre']
  1203. = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  1204. && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
  1205. if ($directionCondition) {
  1206. $button_html .= '<th ' . $colspan . '>'
  1207. . $full_or_partial_text_link . '</th>';
  1208. // end horizontal/horizontalflipped mode
  1209. } else {
  1210. $vertical_display['textbtn']
  1211. = ' <th ' . $rowspan . ' class="vmiddle">' . "\n"
  1212. . ' ' . "\n"
  1213. . ' </th>' . "\n";
  1214. } // end vertical mode
  1215. } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
  1216. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  1217. && (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  1218. || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
  1219. ) {
  1220. // ... elseif no button, displays empty(ies) col(s) if required
  1221. $vertical_display['emptypre']
  1222. = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  1223. && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
  1224. if ($directionCondition) {
  1225. $button_html .= '<td ' . $colspan . '></td>';
  1226. // end horizontal/horizontalfipped mode
  1227. } else {
  1228. $vertical_display['textbtn'] = ' <td' . $rowspan .
  1229. '></td>' . "\n";
  1230. } // end vertical mode
  1231. } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE)
  1232. && ($directionCondition)
  1233. ) {
  1234. // ... elseif display an empty column if the actions links are
  1235. // disabled to match the rest of the table
  1236. $button_html .= '<th></th>';
  1237. }
  1238. $this->__set('vertical_display', $vertical_display);
  1239. return array($colspan, $rowspan, $button_html);
  1240. } // end of the '_getFieldVisibilityParams()' function
  1241. /**
  1242. * Get table comments as array
  1243. *
  1244. * @param boolean $direction display direction, horizontal
  1245. * or horizontalflipped
  1246. * @param array $analyzed_sql the analyzed query
  1247. *
  1248. * @return array $comments_map table comments when condition true
  1249. * null when condition falls
  1250. *
  1251. * @access private
  1252. *
  1253. * @see _getTableHeaders()
  1254. */
  1255. private function _getTableCommentsArray($direction, $analyzed_sql)
  1256. {
  1257. $comments_map = null;
  1258. if ($GLOBALS['cfg']['ShowBrowseComments']
  1259. && ($direction != self::DISP_DIR_HORIZONTAL_FLIPPED)
  1260. ) {
  1261. $comments_map = array();
  1262. if (isset($analyzed_sql[0])
  1263. && is_array($analyzed_sql[0])
  1264. && isset($analyzed_sql[0]['table_ref'])
  1265. ) {
  1266. foreach ($analyzed_sql[0]['table_ref'] as $tbl) {
  1267. $tb = $tbl['table_true_name'];
  1268. $comments_map[$tb] = PMA_getComments($this->__get('db'), $tb);
  1269. unset($tb);
  1270. }
  1271. }
  1272. }
  1273. return $comments_map;
  1274. } // end of the '_getTableCommentsArray()' function
  1275. /**
  1276. * Set global array for store highlighted header fields
  1277. *
  1278. * @param array $analyzed_sql the analyzed query
  1279. *
  1280. * @return void
  1281. *
  1282. * @access private
  1283. *
  1284. * @see _getTableHeaders()
  1285. */
  1286. private function _setHighlightedColumnGlobalField($analyzed_sql)
  1287. {
  1288. $highlight_columns = array();
  1289. if (isset($analyzed_sql) && isset($analyzed_sql[0])
  1290. && isset($analyzed_sql[0]['where_clause_identifiers'])
  1291. && is_array($analyzed_sql[0]['where_clause_identifiers'])
  1292. ) {
  1293. foreach ($analyzed_sql[0]['where_clause_identifiers'] as $wci) {
  1294. $highlight_columns[$wci] = 'true';
  1295. }
  1296. }
  1297. $this->__set('highlight_columns', $highlight_columns);
  1298. } // end of the '_setHighlightedColumnGlobalField()' function
  1299. /**
  1300. * Prepare data for column restoring and show/hide
  1301. *
  1302. * @return string $data_html html content
  1303. *
  1304. * @access private
  1305. *
  1306. * @see _getTableHeaders()
  1307. */
  1308. private function _getDataForResettingColumnOrder()
  1309. {
  1310. $data_html = '';
  1311. // generate the column order, if it is set
  1312. $pmatable = new PMA_Table($this->__get('table'), $this->__get('db'));
  1313. $col_order = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_ORDER);
  1314. if ($col_order) {
  1315. $data_html .= '<input id="col_order" type="hidden" value="'
  1316. . implode(',', $col_order) . '" />';
  1317. }
  1318. $col_visib = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_VISIB);
  1319. if ($col_visib) {
  1320. $data_html .= '<input id="col_visib" type="hidden" value="'
  1321. . implode(',', $col_visib) . '" />';
  1322. }
  1323. // generate table create time
  1324. if (! PMA_Table::isView($this->__get('db'), $this->__get('table'))) {
  1325. $data_html .= '<input id="table_create_time" type="hidden" value="'
  1326. . PMA_Table::sGetStatusInfo(
  1327. $this->__get('db'), $this->__get('table'), 'Create_time'
  1328. ) . '" />';
  1329. }
  1330. return $data_html;
  1331. } // end of the '_getDataForResettingColumnOrder()' function
  1332. /**
  1333. * Prepare option fields block
  1334. *
  1335. * @return string $options_html html content
  1336. *
  1337. * @access private
  1338. *
  1339. * @see _getTableHeaders()
  1340. */
  1341. private function _getOptionsBlock()
  1342. {
  1343. $options_html = '';
  1344. $options_html .= '<form method="post" action="sql.php" '
  1345. . 'name="displayOptionsForm" '
  1346. . 'id="displayOptionsForm"';
  1347. $options_html .= ' class="ajax" ';
  1348. $options_html .= '>';
  1349. $url_params = array(
  1350. 'db' => $this->__get('db'),
  1351. 'table' => $this->__get('table'),
  1352. 'sql_query' => $this->__get('sql_query'),
  1353. 'goto' => $this->__get('goto'),
  1354. 'display_options_form' => 1
  1355. );
  1356. $options_html .= PMA_URL_getHiddenInputs($url_params)
  1357. . '<br />'
  1358. . PMA_Util::getDivForSliderEffect(
  1359. 'displayoptions', __('Options')
  1360. )
  1361. . '<fieldset>';
  1362. $options_html .= '<div class="formelement">';
  1363. $choices = array(
  1364. 'P' => __('Partial texts'),
  1365. 'F' => __('Full texts')
  1366. );
  1367. // pftext means "partial or full texts" (done to reduce line lengths)
  1368. $options_html .= PMA_Util::getRadioFields(
  1369. 'pftext', $choices,
  1370. $_SESSION['tmpval']['pftext']
  1371. )
  1372. . '</div>';
  1373. if ($GLOBALS['cfgRelation']['relwork']
  1374. && $GLOBALS['cfgRelation']['displaywork']
  1375. ) {
  1376. $options_html .= '<div class="formelement">';
  1377. $choices = array(
  1378. 'K' => __('Relational key'),
  1379. 'D' => __('Relational display column')
  1380. );
  1381. $options_html .= PMA_Util::getRadioFields(
  1382. 'relational_display', $choices,
  1383. $_SESSION['tmpval']['relational_display']
  1384. )
  1385. . '</div>';
  1386. }
  1387. $options_html .= '<div class="formelement">'
  1388. . PMA_Util::getCheckbox(
  1389. 'display_binary', __('Show binary contents'),
  1390. ! empty($_SESSION['tmpval']['display_binary']), false
  1391. )
  1392. . '<br />'
  1393. . PMA_Util::getCheckbox(
  1394. 'display_blob', __('Show BLOB contents'),
  1395. ! empty($_SESSION['tmpval']['display_blob']), false
  1396. )
  1397. . '<br />'
  1398. . PMA_Util::getCheckbox(
  1399. 'display_binary_as_hex', __('Show binary contents as HEX'),
  1400. ! empty($_SESSION['tmpval']['display_binary_as_hex']), false
  1401. )
  1402. . '</div>';
  1403. // I would have preferred to name this "display_transformation".
  1404. // This is the only way I found to be able to keep this setting sticky
  1405. // per SQL query, and at the same time have a default that displays
  1406. // the transformations.
  1407. $options_html .= '<div class="formelement">'
  1408. . PMA_Util::getCheckbox(
  1409. 'hide_transformation', __('Hide browser transformation'),
  1410. ! empty($_SESSION['tmpval']['hide_transformation']), false
  1411. )
  1412. . '</div>';
  1413. if (! PMA_DRIZZLE) {
  1414. $options_html .= '<div class="formelement">';
  1415. $choices = array(
  1416. 'GEOM' => __('Geometry'),
  1417. 'WKT' => __('Well Known Text'),
  1418. 'WKB' => __('Well Known Binary')
  1419. );
  1420. $options_html .= PMA_Util::getRadioFields(
  1421. 'geoOption', $choices,
  1422. $_SESSION['tmpval']['geoOption']
  1423. )
  1424. . '</div>';
  1425. }
  1426. $options_html .= '<div class="clearfloat"></div>'
  1427. . '</fieldset>';
  1428. $options_html .= '<fieldset class="tblFooters">'
  1429. . '<input type="submit" value="' . __('Go') . '" />'
  1430. . '</fieldset>'
  1431. . '</div>'
  1432. . '</form>';
  1433. return $options_html;
  1434. } // end of the '_getOptionsBlock()' function
  1435. /**
  1436. * Get full/partial text button or link
  1437. *
  1438. * @return string html content
  1439. *
  1440. * @access private
  1441. *
  1442. * @see _getTableHeaders()
  1443. */
  1444. private function _getFullOrPartialTextButtonOrLink()
  1445. {
  1446. $url_params_full_text = array(
  1447. 'db' => $this->__get('db'),
  1448. 'table' => $this->__get('table'),
  1449. 'sql_query' => $this->__get('sql_query'),
  1450. 'goto' => $this->__get('goto'),
  1451. 'full_text_button' => 1
  1452. );
  1453. if ($_SESSION['tmpval']['pftext'] == self::DISPLAY_FULL_TEXT) {
  1454. // currently in fulltext mode so show the opposite link
  1455. $tmp_image_file = $this->__get('pma_theme_image') . 's_partialtext.png';
  1456. $tmp_txt = __('Partial texts');
  1457. $url_params_full_text['pftext'] = self::DISPLAY_PARTIAL_TEXT;
  1458. } else {
  1459. $tmp_image_file = $this->__get('pma_theme_image') . 's_fulltext.png';
  1460. $tmp_txt = __('Full texts');
  1461. $url_params_full_text['pftext'] = self::DISPLAY_FULL_TEXT;
  1462. }
  1463. $tmp_image = '<img class="fulltext" src="' . $tmp_image_file . '" alt="'
  1464. . $tmp_txt . '" title="' . $tmp_txt . '" />';
  1465. $tmp_url = 'sql.php' . PMA_URL_getCommon($url_params_full_text);
  1466. return PMA_Util::linkOrButton(
  1467. $tmp_url, $tmp_image, array(), false
  1468. );
  1469. } // end of the '_getFullOrPartialTextButtonOrLink()' function
  1470. /**
  1471. * Prepare html form for multi row operations
  1472. *
  1473. * @param string $del_lnk the delete link of current row
  1474. *
  1475. * @return string $form_html html content
  1476. *
  1477. * @access private
  1478. *
  1479. * @see _getTableHeaders()
  1480. */
  1481. private function _getFormForMultiRowOperations($del_lnk)
  1482. {
  1483. $form_html = '';
  1484. if (($del_lnk == self::DELETE_ROW) || ($del_lnk == self::KILL_PROCESS)) {
  1485. $form_html .= '<form method="post" action="tbl_row_action.php" '
  1486. . 'name="resultsForm" id="resultsForm"';
  1487. $form_html .= ' class="ajax" ';
  1488. $form_html .= '>'
  1489. . PMA_URL_getHiddenInputs(
  1490. $this->__get('db'), $this->__get('table'), 1
  1491. )
  1492. . '<input type="hidden" name="goto" value="sql.php" />';
  1493. }
  1494. $form_html .= '<table id="table_results" class="data';
  1495. $form_html .= ' ajax';
  1496. $form_html .= '">';
  1497. return $form_html;
  1498. } // end of the '_getFormForMultiRowOperations()' function
  1499. /**
  1500. * Get comment for row
  1501. *
  1502. * @param array $comments_map comments array
  1503. * @param array $fields_meta set of field properties
  1504. *
  1505. * @return string $comment html content
  1506. *
  1507. * @access private
  1508. *
  1509. * @see _getTableHeaders()
  1510. */
  1511. private function _getCommentForRow($comments_map, $fields_meta)
  1512. {
  1513. $comments = '';
  1514. if (isset($comments_map)
  1515. && isset($comments_map[$fields_meta->table])
  1516. && isset($comments_map[$fields_meta->table][$fields_meta->name])
  1517. ) {
  1518. $comments = '<span class="tblcomment">'
  1519. . htmlspecialchars(
  1520. $comments_map[$fields_meta->table][$fields_meta->name]
  1521. )
  1522. . '</span>';
  1523. }
  1524. return $comments;
  1525. } // end of the '_getCommentForRow()' function
  1526. /**
  1527. * Prepare parameters and html for sorted table header fields
  1528. *
  1529. * @param array $fields_meta set of field properties
  1530. * @param array $sort_expression sort expression
  1531. * @param array $sort_expression_nodirection sort expression without direction
  1532. * @param integer $column_index the index of the column
  1533. * @param string $unsorted_sql_query the unsorted sql query
  1534. * @param integer $session_max_rows maximum rows resulted by sql
  1535. * @param string $direction the display direction
  1536. * @param string $comments comment for row
  1537. * @param array $sort_direction sort direction
  1538. * @param boolean $directionCondition display direction horizontal
  1539. * or horizontalflipped
  1540. * @param boolean $col_visib column is visible(false)
  1541. * array column isn't visible(string array)
  1542. * @param string $col_visib_j element of $col_visib array
  1543. *
  1544. * @return array 2 element array - $order_link, $sorted_header_html
  1545. *
  1546. * @access private
  1547. *
  1548. * @see _getTableHeaders()
  1549. */
  1550. private function _getOrderLinkAndSortedHeaderHtml(
  1551. $fields_meta, $sort_expression, $sort_expression_nodirection,
  1552. $column_index, $unsorted_sql_query, $session_max_rows, $direction,
  1553. $comments, $sort_direction, $directionCondition, $col_visib, $col_visib_j
  1554. ) {
  1555. $sorted_header_html = '';
  1556. // Checks if the table name is required; it's the case
  1557. // for a query with a "JOIN" statement and if the column
  1558. // isn't aliased, or in queries like
  1559. // SELECT `1`.`master_field` , `2`.`master_field`
  1560. // FROM `PMA_relation` AS `1` , `PMA_relation` AS `2`
  1561. $sort_tbl = (isset($fields_meta->table)
  1562. && strlen($fields_meta->table))
  1563. ? PMA_Util::backquote(
  1564. $fields_meta->table
  1565. ) . '.'
  1566. : '';
  1567. $name_to_use_in_sort = $fields_meta->name;
  1568. // Generates the orderby clause part of the query which is part
  1569. // of URL
  1570. list($single_sort_order, $multi_sort_order, $order_img) = $this->_getSingleAndMultiSortUrls(
  1571. $sort_expression, $sort_expression_nodirection, $sort_tbl,
  1572. $name_to_use_in_sort, $sort_direction, $fields_meta, $column_index
  1573. );
  1574. if (preg_match(
  1575. '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|FOR UPDATE|'
  1576. . 'LOCK IN SHARE MODE))@is',
  1577. $unsorted_sql_query, $regs3
  1578. )) {
  1579. $single_sorted_sql_query = $regs3[1] . $single_sort_order . $regs3[2];
  1580. $multi_sorted_sql_query = $regs3[1] . $multi_sort_order . $regs3[2];
  1581. } else {
  1582. $single_sorted_sql_query = $unsorted_sql_query . $single_sort_order;
  1583. $multi_sorted_sql_query = $unsorted_sql_query . $multi_sort_order;
  1584. }
  1585. $_single_url_params = array(
  1586. 'db' => $this->__get('db'),
  1587. 'table' => $this->__get('table'),
  1588. 'sql_query' => $single_sorted_sql_query,
  1589. 'session_max_rows' => $session_max_rows
  1590. );
  1591. $_multi_url_params = array(
  1592. 'db' => $this->__get('db'),
  1593. 'table' => $this->__get('table'),
  1594. 'sql_query' => $multi_sorted_sql_query,
  1595. 'session_max_rows' => $session_max_rows
  1596. );
  1597. $single_order_url = 'sql.php' . PMA_URL_getCommon($_single_url_params);
  1598. $multi_order_url = 'sql.php' . PMA_URL_getCommon($_multi_url_params);
  1599. // Displays the sorting URL
  1600. // enable sort order swapping for image
  1601. $order_link = $this->_getSortOrderLink(
  1602. $order_img, $column_index, $direction,
  1603. $fields_meta, $single_order_url, $multi_order_url
  1604. );
  1605. $sorted_header_html .= $this->_getDraggableClassForSortableColumns(
  1606. $col_visib, $col_visib_j, $direction,
  1607. $fields_meta, $order_link, $comments
  1608. );
  1609. return array($order_link, $sorted_header_html);
  1610. } // end of the '_getOrderLinkAndSortedHeaderHtml()' function
  1611. /**
  1612. * Prepare parameters and html for sorted table header fields
  1613. *
  1614. * @param array $sort_expression sort expression
  1615. * @param array $sort_expression_nodirection sort expression without direction
  1616. * @param string $sort_tbl The name of the table to which
  1617. * the current column belongs to
  1618. * @param string $name_to_use_in_sort The current column under
  1619. * consideration
  1620. * @param array $sort_direction sort direction
  1621. * @param array $fields_meta set of field properties
  1622. * @param integer $column_index The index number to current column
  1623. *
  1624. * @return array 3 element array - $single_sort_order, $sort_order, $order_img
  1625. *
  1626. * @access private
  1627. *
  1628. * @see _getOrderLinkAndSortedHeaderHtml()
  1629. */
  1630. private function _getSingleAndMultiSortUrls(
  1631. $sort_expression, $sort_expression_nodirection, $sort_tbl,
  1632. $name_to_use_in_sort, $sort_direction, $fields_meta, $column_index
  1633. ) {
  1634. $sort_order = "";
  1635. // Check if the current column is in the order by clause
  1636. $is_in_sort = $this->_isInSorted(
  1637. $sort_expression, $sort_expression_nodirection,
  1638. $sort_tbl, $name_to_use_in_sort
  1639. );
  1640. $current_name = $name_to_use_in_sort;
  1641. if ($sort_expression_nodirection[0] == '' || !$is_in_sort) {
  1642. $special_index = $sort_expression_nodirection[0] == ''
  1643. ? 0
  1644. : count($sort_expression_nodirection);
  1645. $sort_expression_nodirection[$special_index]
  1646. = PMA_Util::backquote(
  1647. $current_name
  1648. );
  1649. $sort_direction[$special_index] = (preg_match(
  1650. '@time|date@i',
  1651. $fields_meta->type
  1652. )) ? self::DESCENDING_SORT_DIR : self::ASCENDING_SORT_DIR;
  1653. }
  1654. $sort_expression_nodirection = array_filter($sort_expression_nodirection);
  1655. foreach ($sort_expression_nodirection as $index=>$expression) {
  1656. // check if this is the first clause,
  1657. // if it is then we have to add "order by"
  1658. $is_first_clause = ($index == 0);
  1659. $name_to_use_in_sort = $expression;
  1660. $sort_tbl_new = $sort_tbl;
  1661. // Test to detect if the column name is a standard name
  1662. // Standard name has the table name prefixed to the column name
  1663. $is_standard_name = false;
  1664. if (strpos($name_to_use_in_sort, '.') !== false) {
  1665. $matches = explode('.', $name_to_use_in_sort);
  1666. // Matches[0] has the table name
  1667. // Matches[1] has the column name
  1668. $name_to_use_in_sort = $matches[1];
  1669. $sort_tbl_new = $matches[0];
  1670. $is_standard_name = true;
  1671. }
  1672. // $name_to_use_in_sort might contain a space due to
  1673. // formatting of function expressions like "COUNT(name )"
  1674. // so we remove the space in this situation
  1675. $name_to_use_in_sort = str_replace(' )', ')', $name_to_use_in_sort);
  1676. $name_to_use_in_sort = str_replace('`', '', $name_to_use_in_sort);
  1677. // If this the first column name in the order by clause add
  1678. // order by clause to the column name
  1679. $query_head = $is_first_clause ? "\nORDER BY " : "";
  1680. $tbl = $is_standard_name ? $sort_tbl_new : $sort_tbl;
  1681. // Again a check to see if the given column is a aggregate column
  1682. if (strpos($name_to_use_in_sort, '(') !== false) {
  1683. $sort_order .= $query_head . $name_to_use_in_sort . ' ' ;
  1684. } else {
  1685. $sort_order .= $query_head . $sort_tbl_new . "."
  1686. . PMA_Util::backquote(
  1687. $name_to_use_in_sort
  1688. ) . ' ' ;
  1689. }
  1690. // For a special case where the code generates two dots between
  1691. // column name and table name.
  1692. $sort_order = preg_replace("/\.\./", ".", $sort_order);
  1693. // Incase this is the current column save $single_sort_order
  1694. if ($current_name == $name_to_use_in_sort) {
  1695. if (strpos($current_name, '(') !== false) {
  1696. $single_sort_order = "\n" . 'ORDER BY ' . $current_name . ' ';
  1697. } else {
  1698. $single_sort_order = "\n" . 'ORDER BY ' . $sort_tbl
  1699. . PMA_Util::backquote(
  1700. $current_name
  1701. ) . ' ';
  1702. }
  1703. if ($is_in_sort) {
  1704. list($single_sort_order, $order_img) = $this->_getSortingUrlParams(
  1705. $sort_direction, $single_sort_order, $column_index, $index
  1706. );
  1707. } else {
  1708. $single_sort_order .= strtoupper($sort_direction[$index]);
  1709. }
  1710. }
  1711. if ($current_name == $name_to_use_in_sort && $is_in_sort) {
  1712. // We need to generate the arrow button and related html
  1713. list($sort_order, $order_img) = $this->_getSortingUrlParams(
  1714. $sort_direction, $sort_order, $column_index, $index
  1715. );
  1716. $order_img .= " <small>" . ($index + 1) . "</small>";
  1717. } else {
  1718. $sort_order .= strtoupper($sort_direction[$index]);
  1719. }
  1720. // Separate columns by a comma
  1721. $sort_order .= ", ";
  1722. unset($name_to_use_in_sort);
  1723. }
  1724. // remove the comma from the last column name in the newly
  1725. // constructed clause
  1726. $sort_order = substr($sort_order, 0, strlen($sort_order)-2);
  1727. if (empty($order_img)) {
  1728. $order_img = '';
  1729. }
  1730. return array($single_sort_order, $sort_order, $order_img);
  1731. }
  1732. /**
  1733. * Check whether the column is sorted
  1734. *
  1735. * @param array $sort_expression sort expression
  1736. * @param array $sort_expression_nodirection sort expression without direction
  1737. * @param string $sort_tbl the table name
  1738. * @param string $name_to_use_in_sort the sorting column name
  1739. *
  1740. * @return boolean $is_in_sort the column sorted or not
  1741. *
  1742. * @access private
  1743. *
  1744. * @see _getTableHeaders()
  1745. */
  1746. private function _isInSorted(
  1747. $sort_expression, $sort_expression_nodirection, $sort_tbl,
  1748. $name_to_use_in_sort
  1749. ) {
  1750. $index_in_expression = 0;
  1751. foreach ($sort_expression_nodirection as $index => $clause) {
  1752. if (strpos($clause, '.') !== false) {
  1753. $fragments = explode('.', $clause);
  1754. $clause2 = $fragments[0] . "." . str_replace('`', '', $fragments[1]);
  1755. } else {
  1756. $clause2 = $sort_tbl . str_replace('`', '', $clause);
  1757. }
  1758. if ($clause2 === $sort_tbl . $name_to_use_in_sort) {
  1759. $index_in_expression = $index;
  1760. break;
  1761. }
  1762. }
  1763. if (empty($sort_expression[$index_in_expression])) {
  1764. $is_in_sort = false;
  1765. } else {
  1766. // Field name may be preceded by a space, or any number
  1767. // of characters followed by a dot (tablename.fieldname)
  1768. // so do a direct comparison for the sort expression;
  1769. // this avoids problems with queries like
  1770. // "SELECT id, count(id)..." and clicking to sort
  1771. // on id or on count(id).
  1772. // Another query to test this:
  1773. // SELECT p.*, FROM_UNIXTIME(p.temps) FROM mytable AS p
  1774. // (and try clicking on each column's header twice)
  1775. if (! empty($sort_tbl)
  1776. && strpos($sort_expression_nodirection[$index_in_expression], $sort_tbl) === false
  1777. && strpos($sort_expression_nodirection[$index_in_expression], '(') === false
  1778. ) {
  1779. $new_sort_expression_nodirection = $sort_tbl
  1780. . $sort_expression_nodirection[$index_in_expression];
  1781. } else {
  1782. $new_sort_expression_nodirection
  1783. = $sort_expression_nodirection[$index_in_expression];
  1784. }
  1785. //Back quotes are removed in next comparison, so remove them from value
  1786. //to compare.
  1787. $name_to_use_in_sort = str_replace('`', '', $name_to_use_in_sort);
  1788. $is_in_sort = false;
  1789. $sort_name = str_replace('`', '', $sort_tbl) . $name_to_use_in_sort;
  1790. if ($sort_name == str_replace('`', '', $new_sort_expression_nodirection)
  1791. || $sort_name == str_replace('`', '', $sort_expression_nodirection[$index_in_expression])
  1792. ) {
  1793. $is_in_sort = true;
  1794. }
  1795. }
  1796. return $is_in_sort;
  1797. } // end of the '_isInSorted()' function
  1798. /**
  1799. * Get sort url paramaeters - sort order and order image
  1800. *
  1801. * @param array $sort_direction the sort direction
  1802. * @param string $sort_order the sorting order
  1803. * @param integer $column_index the index of the column
  1804. * @param integer $index the index of sort direction array.
  1805. *
  1806. * @return array 2 element array - $sort_order, $order_img
  1807. *
  1808. * @access private
  1809. *
  1810. * @see _getSingleAndMultiSortUrls()
  1811. */
  1812. private function _getSortingUrlParams(
  1813. $sort_direction, $sort_order, $column_index, $index
  1814. ) {
  1815. if (strtoupper(trim($sort_direction[$index])) == self::DESCENDING_SORT_DIR) {
  1816. $sort_order .= ' ASC';
  1817. $order_img = ' ' . PMA_Util::getImage(
  1818. 's_desc.png', __('Descending'),
  1819. array('class' => "soimg$column_index", 'title' => '')
  1820. );
  1821. $order_img .= ' ' . PMA_Util::getImage(
  1822. 's_asc.png', __('Ascending'),
  1823. array('class' => "soimg$column_index hide", 'title' => '')
  1824. );
  1825. } else {
  1826. $sort_order .= ' DESC';
  1827. $order_img = ' ' . PMA_Util::getImage(
  1828. 's_asc.png', __('Ascending'),
  1829. array('class' => "soimg$column_index", 'title' => '')
  1830. );
  1831. $order_img .= ' ' . PMA_Util::getImage(
  1832. 's_desc.png', __('Descending'),
  1833. array('class' => "soimg$column_index hide", 'title' => '')
  1834. );
  1835. }
  1836. return array($sort_order, $order_img);
  1837. } // end of the '_getSortingUrlParams()' function
  1838. /**
  1839. * Get sort order link
  1840. *
  1841. * @param string $order_img the sort order image
  1842. * @param integer $col_index the index of the column
  1843. * @param string $direction the display direction
  1844. * @param array $fields_meta set of field properties
  1845. * @param string $order_url the url for sort
  1846. * @param string $multi_order_url the url for sort
  1847. *
  1848. * @return string the sort order link
  1849. *
  1850. * @access private
  1851. *
  1852. * @see _getTableHeaders()
  1853. */
  1854. private function _getSortOrderLink(
  1855. $order_img, $col_index, $direction, $fields_meta, $order_url, $multi_order_url
  1856. ) {
  1857. $order_link_params = array();
  1858. if (isset($order_img) && ($order_img != '')) {
  1859. if (strstr($order_img, 'asc')) {
  1860. $order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()";
  1861. $order_link_params['onmouseout'] = "$('.soimg$col_index').toggle()";
  1862. } elseif (strstr($order_img, 'desc')) {
  1863. $order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()";
  1864. $order_link_params['onmouseout'] = "$('.soimg$col_index').toggle()";
  1865. }
  1866. }
  1867. if ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_AUTO) {
  1868. $GLOBALS['cfg']['HeaderFlipType']
  1869. = (PMA_USR_BROWSER_AGENT == 'IE')
  1870. ? self::HEADER_FLIP_TYPE_CSS
  1871. : self::HEADER_FLIP_TYPE_FAKE;
  1872. }
  1873. if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED
  1874. && $GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_CSS
  1875. ) {
  1876. $order_link_params['style'] = 'direction: ltr; writing-mode: tb-rl;';
  1877. }
  1878. $order_link_content = (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED)
  1879. && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_FAKE))
  1880. ? PMA_Util::flipstring(
  1881. htmlspecialchars($fields_meta->name),
  1882. "<br />\n"
  1883. )
  1884. : htmlspecialchars($fields_meta->name);
  1885. $inner_link_content = $order_link_content . $order_img
  1886. . '<input type="hidden" value="' . $multi_order_url . '" />';
  1887. return PMA_Util::linkOrButton(
  1888. $order_url, $inner_link_content,
  1889. $order_link_params, false, true
  1890. );
  1891. } // end of the '_getSortOrderLink()' function
  1892. /**
  1893. * Prepare columns to draggable effect for sortable columns
  1894. *
  1895. * @param boolean $col_visib the column is visible (false)
  1896. * array the column is not visible (string array)
  1897. * @param string $col_visib_j element of $col_visib array
  1898. * @param string $direction the display direction
  1899. * @param array $fields_meta set of field properties
  1900. * @param string $order_link the order link
  1901. * @param string $comments the comment for the column
  1902. *
  1903. * @return string $draggable_html html content
  1904. *
  1905. * @access private
  1906. *
  1907. * @see _getTableHeaders()
  1908. */
  1909. private function _getDraggableClassForSortableColumns(
  1910. $col_visib, $col_visib_j, $direction, $fields_meta,
  1911. $order_link, $comments
  1912. ) {
  1913. $draggable_html = '<th';
  1914. $th_class = array();
  1915. $th_class[] = 'draggable';
  1916. if ($col_visib && !$col_visib_j) {
  1917. $th_class[] = 'hide';
  1918. }
  1919. $th_class[] = 'column_heading';
  1920. if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
  1921. $th_class[] = 'pointer';
  1922. }
  1923. if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
  1924. $th_class[] = 'marker';
  1925. }
  1926. $draggable_html .= ' class="' . implode(' ', $th_class);
  1927. if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED) {
  1928. $draggable_html .= ' vbottom';
  1929. }
  1930. $draggable_html .= '" data-column="' . htmlspecialchars($fields_meta->name)
  1931. . '">' . $order_link . $comments . '</th>';
  1932. return $draggable_html;
  1933. } // end of the '_getDraggableClassForSortableColumns()' function
  1934. /**
  1935. * Prepare columns to draggable effect for non sortable columns
  1936. *
  1937. * @param boolean $col_visib the column is visible (false)
  1938. * array the column is not visible (string array)
  1939. * @param string $col_visib_j element of $col_visib array
  1940. * @param boolean $condition_field whether to add CSS class condition
  1941. * @param string $direction the display direction
  1942. * @param array $fields_meta set of field properties
  1943. * @param string $comments the comment for the column
  1944. *
  1945. * @return string $draggable_html html content
  1946. *
  1947. * @access private
  1948. *
  1949. * @see _getTableHeaders()
  1950. */
  1951. private function _getDraggableClassForNonSortableColumns(
  1952. $col_visib, $col_visib_j, $condition_field,
  1953. $direction, $fields_meta, $comments
  1954. ) {
  1955. $draggable_html = '<th';
  1956. $th_class = array();
  1957. $th_class[] = 'draggable';
  1958. if ($col_visib && !$col_visib_j) {
  1959. $th_class[] = 'hide';
  1960. }
  1961. if ($condition_field) {
  1962. $th_class[] = 'condition';
  1963. }
  1964. $draggable_html .= ' class="' . implode(' ', $th_class);
  1965. if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED) {
  1966. $draggable_html .= ' vbottom';
  1967. }
  1968. $draggable_html .= '"';
  1969. if (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED)
  1970. && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_CSS)
  1971. ) {
  1972. $draggable_html .= ' style="direction: ltr; writing-mode: tb-rl;"';
  1973. }
  1974. $draggable_html .= ' data-column="'
  1975. . htmlspecialchars($fields_meta->name) . '">';
  1976. if (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED)
  1977. && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_FAKE)
  1978. ) {
  1979. $draggable_html .= PMA_Util::flipstring(
  1980. htmlspecialchars($fields_meta->name), '<br />'
  1981. );
  1982. } else {
  1983. $draggable_html .= htmlspecialchars($fields_meta->name);
  1984. }
  1985. $draggable_html .= "\n" . $comments . '</th>';
  1986. return $draggable_html;
  1987. } // end of the '_getDraggableClassForNonSortableColumns()' function
  1988. /**
  1989. * Prepare column to show at right side - check boxes or empty column
  1990. *
  1991. * @param array &$is_display which elements to display
  1992. * @param boolean $directionCondition display direction horizontal
  1993. * or horizontalflipped
  1994. * @param string $full_or_partial_text_link full/partial link or text button
  1995. * @param string $colspan column span of table header
  1996. * @param string $rowspan row span of table header
  1997. *
  1998. * @return string html content
  1999. *
  2000. * @access private
  2001. *
  2002. * @see _getTableHeaders()
  2003. */
  2004. private function _getColumnAtRightSide(
  2005. &$is_display, $directionCondition, $full_or_partial_text_link,
  2006. $colspan, $rowspan
  2007. ) {
  2008. $right_column_html = '';
  2009. $vertical_display = $this->__get('vertical_display');
  2010. // Displays the needed checkboxes at the right
  2011. // column of the result table header if possible and required...
  2012. if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
  2013. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  2014. && (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  2015. || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
  2016. && ($is_display['text_btn'] == '1')
  2017. ) {
  2018. $vertical_display['emptyafter']
  2019. = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  2020. && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1;
  2021. if ($directionCondition) {
  2022. $right_column_html .= "\n"
  2023. . '<th ' . $colspan . '>' . $full_or_partial_text_link
  2024. . '</th>';
  2025. // end horizontal/horizontalflipped mode
  2026. } else {
  2027. $vertical_display['textbtn'] = ' <th ' . $rowspan
  2028. . ' class="vmiddle">' . "\n"
  2029. . ' ' . "\n"
  2030. . ' </th>' . "\n";
  2031. } // end vertical mode
  2032. } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
  2033. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  2034. && (($is_display['edit_lnk'] == self::NO_EDIT_OR_DELETE)
  2035. && ($is_display['del_lnk'] == self::NO_EDIT_OR_DELETE))
  2036. && (! isset($GLOBALS['is_header_sent']) || ! $GLOBALS['is_header_sent'])
  2037. ) {
  2038. // ... elseif no button, displays empty columns if required
  2039. // (unless coming from Browse mode print view)
  2040. $vertical_display['emptyafter']
  2041. = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  2042. && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1;
  2043. if ($directionCondition) {
  2044. $right_column_html .= "\n"
  2045. . '<td ' . $colspan . '></td>';
  2046. // end horizontal/horizontalflipped mode
  2047. } else {
  2048. $vertical_display['textbtn'] = ' <td' . $rowspan
  2049. . '></td>' . "\n";
  2050. } // end vertical mode
  2051. }
  2052. $this->__set('vertical_display', $vertical_display);
  2053. return $right_column_html;
  2054. } // end of the '_getColumnAtRightSide()' function
  2055. /**
  2056. * Prepares the display for a value
  2057. *
  2058. * @param string $class class of table cell
  2059. * @param bool $condition_field whether to add CSS class condition
  2060. * @param string $value value to display
  2061. *
  2062. * @return string the td
  2063. *
  2064. * @access private
  2065. *
  2066. * @see _getDataCellForBlobColumns(), _getDataCellForGeometryColumns(),
  2067. * _getDataCellForNonNumericAndNonBlobColumns()
  2068. */
  2069. private function _buildValueDisplay($class, $condition_field, $value)
  2070. {
  2071. return '<td class="left ' . $class . ($condition_field ? ' condition' : '')
  2072. . '">' . $value . '</td>';
  2073. } // end of the '_buildValueDisplay()' function
  2074. /**
  2075. * Prepares the display for a null value
  2076. *
  2077. * @param string $class class of table cell
  2078. * @param bool $condition_field whether to add CSS class condition
  2079. * @param object $meta the meta-information about this field
  2080. * @param string $align cell allignment
  2081. *
  2082. * @return string the td
  2083. *
  2084. * @access private
  2085. *
  2086. * @see _getDataCellForNumericColumns(), _getDataCellForBlobColumns(),
  2087. * _getDataCellForGeometryColumns(),
  2088. * _getDataCellForNonNumericAndNonBlobColumns()
  2089. */
  2090. private function _buildNullDisplay($class, $condition_field, $meta, $align = '')
  2091. {
  2092. // the null class is needed for grid editing
  2093. return '<td ' . $align . ' data-decimals="' . $meta->decimals
  2094. . '" data-type="' . $meta->type . '" class="'
  2095. . $this->_addClass(
  2096. $class, $condition_field, $meta, ''
  2097. )
  2098. . ' null"><i>NULL</i></td>';
  2099. } // end of the '_buildNullDisplay()' function
  2100. /**
  2101. * Prepares the display for an empty value
  2102. *
  2103. * @param string $class class of table cell
  2104. * @param bool $condition_field whether to add CSS class condition
  2105. * @param object $meta the meta-information about this field
  2106. * @param string $align cell allignment
  2107. *
  2108. * @return string the td
  2109. *
  2110. * @access private
  2111. *
  2112. * @see _getDataCellForNumericColumns(), _getDataCellForBlobColumns(),
  2113. * _getDataCellForGeometryColumns(),
  2114. * _getDataCellForNonNumericAndNonBlobColumns()
  2115. */
  2116. private function _buildEmptyDisplay($class, $condition_field, $meta, $align = '')
  2117. {
  2118. return '<td ' . $align . ' class="'
  2119. . $this->_addClass(
  2120. $class, $condition_field, $meta, ' nowrap'
  2121. )
  2122. . '"></td>';
  2123. } // end of the '_buildEmptyDisplay()' function
  2124. /**
  2125. * Adds the relevant classes.
  2126. *
  2127. * @param string $class class of table cell
  2128. * @param bool $condition_field whether to add CSS class condition
  2129. * @param object $meta the meta-information about the field
  2130. * @param string $nowrap avoid wrapping
  2131. * @param bool $is_field_truncated is field truncated (display ...)
  2132. * @param string $transformation_plugin transformation plugin.
  2133. * Can also be the default function:
  2134. * PMA_mimeDefaultFunction
  2135. * @param string $default_function default transformation function
  2136. *
  2137. * @return string the list of classes
  2138. *
  2139. * @access private
  2140. *
  2141. * @see _buildNullDisplay(), _getRowData()
  2142. */
  2143. private function _addClass(
  2144. $class, $condition_field, $meta, $nowrap, $is_field_truncated = false,
  2145. $transformation_plugin = '', $default_function = ''
  2146. ) {
  2147. // Define classes to be added to this data field based on the type of data
  2148. $enum_class = '';
  2149. if (strpos($meta->flags, 'enum') !== false) {
  2150. $enum_class = ' enum';
  2151. }
  2152. $set_class = '';
  2153. if (strpos($meta->flags, 'set') !== false) {
  2154. $set_class = ' set';
  2155. }
  2156. $bit_class = '';
  2157. if (strpos($meta->type, 'bit') !== false) {
  2158. $bit_class = ' bit';
  2159. }
  2160. $mime_type_class = '';
  2161. if (isset($meta->mimetype)) {
  2162. $mime_type_class = ' ' . preg_replace('/\//', '_', $meta->mimetype);
  2163. }
  2164. return $class . ($condition_field ? ' condition' : '') . $nowrap
  2165. . ' ' . ($is_field_truncated ? ' truncated' : '')
  2166. . ($transformation_plugin != $default_function ? ' transformed' : '')
  2167. . $enum_class . $set_class . $bit_class . $mime_type_class;
  2168. } // end of the '_addClass()' function
  2169. /**
  2170. * Prepare the body of the results table
  2171. *
  2172. * @param integer &$dt_result the link id associated to the query
  2173. * which results have to be displayed
  2174. * @param array &$is_display which elements to display
  2175. * @param array $map the list of relations
  2176. * @param array $analyzed_sql the analyzed query
  2177. * @param boolean $is_limited_display with limited operations or not
  2178. *
  2179. * @return string $table_body_html html content
  2180. *
  2181. * @global array $row current row data
  2182. *
  2183. * @access private
  2184. *
  2185. * @see getTable()
  2186. */
  2187. private function _getTableBody(
  2188. &$dt_result, &$is_display, $map, $analyzed_sql, $is_limited_display = false
  2189. ) {
  2190. global $row; // mostly because of browser transformations,
  2191. // to make the row-data accessible in a plugin
  2192. $table_body_html = '';
  2193. // query without conditions to shorten URLs when needed, 200 is just
  2194. // guess, it should depend on remaining URL length
  2195. $url_sql_query = $this->_getUrlSqlQuery($analyzed_sql);
  2196. $vertical_display = $this->__get('vertical_display');
  2197. if (! is_array($map)) {
  2198. $map = array();
  2199. }
  2200. $row_no = 0;
  2201. $vertical_display['edit'] = array();
  2202. $vertical_display['copy'] = array();
  2203. $vertical_display['delete'] = array();
  2204. $vertical_display['data'] = array();
  2205. $vertical_display['row_delete'] = array();
  2206. $this->__set('vertical_display', $vertical_display);
  2207. // name of the class added to all grid editable elements;
  2208. // if we don't have all the columns of a unique key in the result set,
  2209. // do not permit grid editing
  2210. if ($is_limited_display || ! $this->__get('editable')) {
  2211. $grid_edit_class = '';
  2212. } else {
  2213. switch ($GLOBALS['cfg']['GridEditing']) {
  2214. case 'double-click':
  2215. // trying to reduce generated HTML by using shorter
  2216. // classes like click1 and click2
  2217. $grid_edit_class = 'grid_edit click2';
  2218. break;
  2219. case 'click':
  2220. $grid_edit_class = 'grid_edit click1';
  2221. break;
  2222. case 'disabled':
  2223. $grid_edit_class = '';
  2224. break;
  2225. }
  2226. }
  2227. // prepare to get the column order, if available
  2228. list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql);
  2229. // Correction University of Virginia 19991216 in the while below
  2230. // Previous code assumed that all tables have keys, specifically that
  2231. // the phpMyAdmin GUI should support row delete/edit only for such
  2232. // tables.
  2233. // Although always using keys is arguably the prescribed way of
  2234. // defining a relational table, it is not required. This will in
  2235. // particular be violated by the novice.
  2236. // We want to encourage phpMyAdmin usage by such novices. So the code
  2237. // below has been changed to conditionally work as before when the
  2238. // table being displayed has one or more keys; but to display
  2239. // delete/edit options correctly for tables without keys.
  2240. $odd_row = true;
  2241. $directionCondition
  2242. = ($_SESSION['tmpval']['disp_direction']
  2243. == self::DISP_DIR_HORIZONTAL)
  2244. || ($_SESSION['tmpval']['disp_direction']
  2245. == self::DISP_DIR_HORIZONTAL_FLIPPED);
  2246. while ($row = $GLOBALS['dbi']->fetchRow($dt_result)) {
  2247. // "vertical display" mode stuff
  2248. $table_body_html .= $this->_getVerticalDisplaySupportSegments(
  2249. $vertical_display, $row_no, $directionCondition
  2250. );
  2251. $alternating_color_class = ($odd_row ? 'odd' : 'even');
  2252. $odd_row = ! $odd_row;
  2253. if ($directionCondition) {
  2254. // pointer code part
  2255. $table_body_html .= '<tr class="' . $alternating_color_class . '">';
  2256. }
  2257. // 1. Prepares the row
  2258. // 1.1 Results from a "SELECT" statement -> builds the
  2259. // WHERE clause to use in links (a unique key if possible)
  2260. /**
  2261. * @todo $where_clause could be empty, for example a table
  2262. * with only one field and it's a BLOB; in this case,
  2263. * avoid to display the delete and edit links
  2264. */
  2265. list($where_clause, $clause_is_unique, $condition_array)
  2266. = PMA_Util::getUniqueCondition(
  2267. $dt_result,
  2268. $this->__get('fields_cnt'),
  2269. $this->__get('fields_meta'),
  2270. $row
  2271. );
  2272. $where_clause_html = urlencode($where_clause);
  2273. // In print view these variable needs toinitialized
  2274. $del_url = $del_query = $del_str = $edit_anchor_class
  2275. = $edit_str = $js_conf = $copy_url = $copy_str = $edit_url = null;
  2276. // 1.2 Defines the URLs for the modify/delete link(s)
  2277. if (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  2278. || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)
  2279. ) {
  2280. // We need to copy the value
  2281. // or else the == 'both' check will always return true
  2282. if ($GLOBALS['cfg']['ActionLinksMode'] === self::POSITION_BOTH) {
  2283. $iconic_spacer = '<div class="nowrap">';
  2284. } else {
  2285. $iconic_spacer = '';
  2286. }
  2287. // 1.2.1 Modify link(s) - update row case
  2288. if ($is_display['edit_lnk'] == self::UPDATE_ROW) {
  2289. list($edit_url, $copy_url, $edit_str, $copy_str,
  2290. $edit_anchor_class)
  2291. = $this->_getModifiedLinks(
  2292. $where_clause,
  2293. $clause_is_unique, $url_sql_query
  2294. );
  2295. } // end if (1.2.1)
  2296. // 1.2.2 Delete/Kill link(s)
  2297. if (($is_display['del_lnk'] == self::DELETE_ROW)
  2298. || ($is_display['del_lnk'] == self::KILL_PROCESS)
  2299. ) {
  2300. list($del_query, $del_url, $del_str, $js_conf)
  2301. = $this->_getDeleteAndKillLinks(
  2302. $where_clause, $clause_is_unique,
  2303. $url_sql_query, $is_display['del_lnk'],
  2304. $row
  2305. );
  2306. } // end if (1.2.2)
  2307. // 1.3 Displays the links at left if required
  2308. if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
  2309. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  2310. && $directionCondition
  2311. ) {
  2312. $table_body_html .= $this->_getPlacedLinks(
  2313. self::POSITION_LEFT, $del_url, $is_display, $row_no,
  2314. $where_clause, $where_clause_html, $condition_array,
  2315. $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class,
  2316. $edit_str, $copy_str, $del_str, $js_conf
  2317. );
  2318. } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE)
  2319. && $directionCondition
  2320. ) {
  2321. $table_body_html .= $this->_getPlacedLinks(
  2322. self::POSITION_NONE, $del_url, $is_display, $row_no,
  2323. $where_clause, $where_clause_html, $condition_array,
  2324. $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class,
  2325. $edit_str, $copy_str, $del_str, $js_conf
  2326. );
  2327. } // end if (1.3)
  2328. } // end if (1)
  2329. // 2. Displays the rows' values
  2330. $table_body_html .= $this->_getRowValues(
  2331. $dt_result, $row, $row_no, $col_order, $map,
  2332. $grid_edit_class, $col_visib, $where_clause,
  2333. $url_sql_query, $analyzed_sql, $directionCondition
  2334. );
  2335. // 3. Displays the modify/delete links on the right if required
  2336. if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
  2337. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  2338. && $directionCondition
  2339. ) {
  2340. $table_body_html .= $this->_getPlacedLinks(
  2341. self::POSITION_RIGHT, $del_url, $is_display, $row_no,
  2342. $where_clause, $where_clause_html, $condition_array,
  2343. $del_query, 'r', $edit_url, $copy_url, $edit_anchor_class,
  2344. $edit_str, $copy_str, $del_str, $js_conf
  2345. );
  2346. } // end if (3)
  2347. if ($directionCondition) {
  2348. $table_body_html .= '</tr>';
  2349. } // end if
  2350. // 4. Gather links of del_urls and edit_urls in an array for later
  2351. // output
  2352. $this->_gatherLinksForLaterOutputs(
  2353. $row_no, $is_display, $where_clause, $where_clause_html, $js_conf,
  2354. $del_url, $del_query, $del_str, $edit_anchor_class, $edit_url,
  2355. $edit_str, $copy_url, $copy_str, $alternating_color_class,
  2356. $condition_array
  2357. );
  2358. $table_body_html .= $directionCondition ? "\n" : '';
  2359. $row_no++;
  2360. } // end while
  2361. return $table_body_html;
  2362. } // end of the '_getTableBody()' function
  2363. /**
  2364. * Get the values for one data row
  2365. *
  2366. * @param integer &$dt_result the link id associated to the query
  2367. * which results have to be displayed
  2368. * @param array $row current row data
  2369. * @param integer $row_no the index of current row
  2370. * @param array $col_order the column order
  2371. * false when a property not found
  2372. * @param array $map the list of relations
  2373. * @param string $grid_edit_class the class for all editable columns
  2374. * @param boolean $col_visib column is visible(false)
  2375. * array column isn't visible(string array)
  2376. * @param string $where_clause where clause
  2377. * @param string $url_sql_query the analyzed sql query
  2378. * @param array $analyzed_sql the analyzed query
  2379. * @param boolean $directionCondition the directional condition
  2380. *
  2381. * @return string $row_values_html html content
  2382. *
  2383. * @access private
  2384. *
  2385. * @see _getTableBody()
  2386. */
  2387. private function _getRowValues(
  2388. &$dt_result, $row, $row_no, $col_order, $map,
  2389. $grid_edit_class, $col_visib, $where_clause,
  2390. $url_sql_query, $analyzed_sql, $directionCondition
  2391. ) {
  2392. $row_values_html = '';
  2393. // Following variable are needed for use in isset/empty or
  2394. // use with array indexes/safe use in foreach
  2395. $sql_query = $this->__get('sql_query');
  2396. $fields_meta = $this->__get('fields_meta');
  2397. $highlight_columns = $this->__get('highlight_columns');
  2398. $mime_map = $this->__get('mime_map');
  2399. $row_info = $this->_getRowInfoForSpecialLinks($row, $col_order);
  2400. for ($currentColumn = 0;
  2401. $currentColumn < $this->__get('fields_cnt');
  2402. ++$currentColumn) {
  2403. // assign $i with appropriate column order
  2404. $i = $col_order ? $col_order[$currentColumn] : $currentColumn;
  2405. $meta = $fields_meta[$i];
  2406. $not_null_class = $meta->not_null ? 'not_null' : '';
  2407. $relation_class = isset($map[$meta->name]) ? 'relation' : '';
  2408. $hide_class = ($col_visib && ! $col_visib[$currentColumn]
  2409. // hide per <td> only if the display dir is not vertical
  2410. && ($_SESSION['tmpval']['disp_direction']
  2411. != self::DISP_DIR_VERTICAL))
  2412. ? 'hide'
  2413. : '';
  2414. // handle datetime-related class, for grid editing
  2415. $field_type_class
  2416. = $this->_getClassForDateTimeRelatedFields($meta->type);
  2417. $is_field_truncated = false;
  2418. // combine all the classes applicable to this column's value
  2419. $class = $this->_getClassesForColumn(
  2420. $grid_edit_class, $not_null_class, $relation_class,
  2421. $hide_class, $field_type_class, $row_no
  2422. );
  2423. // See if this column should get highlight because it's used in the
  2424. // where-query.
  2425. $condition_field = (isset($highlight_columns)
  2426. && (isset($highlight_columns[$meta->name])
  2427. || isset($highlight_columns[PMA_Util::backquote($meta->name)])))
  2428. ? true
  2429. : false;
  2430. // Wrap MIME-transformations. [MIME]
  2431. $default_function = '_mimeDefaultFunction'; // default_function
  2432. $transformation_plugin = $default_function;
  2433. $transform_options = array();
  2434. if ($GLOBALS['cfgRelation']['mimework']
  2435. && $GLOBALS['cfg']['BrowseMIME']
  2436. ) {
  2437. if (isset($mime_map[$meta->name]['mimetype'])
  2438. && isset($mime_map[$meta->name]['transformation'])
  2439. && !empty($mime_map[$meta->name]['transformation'])
  2440. ) {
  2441. $file = $mime_map[$meta->name]['transformation'];
  2442. $include_file = 'libraries/plugins/transformations/' . $file;
  2443. if (file_exists($include_file)) {
  2444. include_once $include_file;
  2445. $class_name = str_replace('.class.php', '', $file);
  2446. // todo add $plugin_manager
  2447. $plugin_manager = null;
  2448. $transformation_plugin = new $class_name(
  2449. $plugin_manager
  2450. );
  2451. $transform_options = PMA_Transformation_getOptions(
  2452. isset($mime_map[$meta->name]
  2453. ['transformation_options']
  2454. )
  2455. ? $mime_map[$meta->name]
  2456. ['transformation_options']
  2457. : ''
  2458. );
  2459. $meta->mimetype = str_replace(
  2460. '_', '/',
  2461. $mime_map[$meta->name]['mimetype']
  2462. );
  2463. } // end if file_exists
  2464. } // end if transformation is set
  2465. } // end if mime/transformation works.
  2466. $_url_params = array(
  2467. 'db' => $this->__get('db'),
  2468. 'table' => $this->__get('table'),
  2469. 'where_clause' => $where_clause,
  2470. 'transform_key' => $meta->name,
  2471. );
  2472. if (! empty($sql_query)) {
  2473. $_url_params['sql_query'] = $url_sql_query;
  2474. }
  2475. $transform_options['wrapper_link']
  2476. = PMA_URL_getCommon($_url_params);
  2477. $vertical_display = $this->__get('vertical_display');
  2478. // Check whether the field needs to display with syntax highlighting
  2479. if (! empty($this->transformation_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)])
  2480. && (trim($row[$i]) != '')
  2481. ) {
  2482. $row[$i] = PMA_Util::formatSql($row[$i]);
  2483. include_once $this->transformation_info
  2484. [strtolower($this->__get('db'))]
  2485. [strtolower($this->__get('table'))]
  2486. [strtolower($meta->name)][0];
  2487. $transformation_plugin = new $this->transformation_info
  2488. [strtolower($this->__get('db'))]
  2489. [strtolower($this->__get('table'))]
  2490. [strtolower($meta->name)][1](null);
  2491. $transform_options = PMA_Transformation_getOptions(
  2492. isset($mime_map[$meta->name]['transformation_options'])
  2493. ? $mime_map[$meta->name]['transformation_options']
  2494. : ''
  2495. );
  2496. $meta->mimetype = str_replace(
  2497. '_', '/',
  2498. $this->transformation_info[strtolower($this->__get('db'))]
  2499. [strtolower($this->__get('table'))]
  2500. [strtolower($meta->name)][2]
  2501. );
  2502. }
  2503. // Check for the predefined fields need to show as link in schemas
  2504. include_once 'libraries/special_schema_links.lib.php';
  2505. if (isset($GLOBALS['special_schema_links'])
  2506. && (! empty($GLOBALS['special_schema_links'][strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)]))
  2507. ) {
  2508. $linking_url = $this->_getSpecialLinkUrl(
  2509. $row[$i], $row_info, strtolower($meta->name)
  2510. );
  2511. include_once
  2512. "libraries/plugins/transformations/Text_Plain_Link.class.php";
  2513. $transformation_plugin = new Text_Plain_Link(null);
  2514. $transform_options = array(
  2515. 0 => $linking_url,
  2516. 2 => true
  2517. );
  2518. $meta->mimetype = str_replace(
  2519. '_', '/',
  2520. 'Text/Plain'
  2521. );
  2522. }
  2523. if ($meta->numeric == 1) {
  2524. // n u m e r i c
  2525. $vertical_display['data'][$row_no][$i]
  2526. = $this->_getDataCellForNumericColumns(
  2527. $row[$i], $class, $condition_field, $meta, $map,
  2528. $is_field_truncated, $analyzed_sql,
  2529. $transformation_plugin, $default_function,
  2530. $transform_options
  2531. );
  2532. } elseif (stristr($meta->type, self::BLOB_FIELD)) {
  2533. // b l o b
  2534. // PMA_mysql_fetch_fields returns BLOB in place of
  2535. // TEXT fields type so we have to ensure it's really a BLOB
  2536. $field_flags = $GLOBALS['dbi']->fieldFlags($dt_result, $i);
  2537. $vertical_display['data'][$row_no][$i]
  2538. = $this->_getDataCellForBlobColumns(
  2539. $row[$i], $class, $meta, $_url_params, $field_flags,
  2540. $transformation_plugin, $default_function,
  2541. $transform_options, $condition_field, $is_field_truncated
  2542. );
  2543. } elseif ($meta->type == self::GEOMETRY_FIELD) {
  2544. // g e o m e t r y
  2545. // Remove 'grid_edit' from $class as we do not allow to
  2546. // inline-edit geometry data.
  2547. $class = str_replace('grid_edit', '', $class);
  2548. $vertical_display['data'][$row_no][$i]
  2549. = $this->_getDataCellForGeometryColumns(
  2550. $row[$i], $class, $meta, $map, $_url_params,
  2551. $condition_field, $transformation_plugin,
  2552. $default_function, $transform_options,
  2553. $is_field_truncated, $analyzed_sql
  2554. );
  2555. } else {
  2556. // n o t n u m e r i c a n d n o t B L O B
  2557. $vertical_display['data'][$row_no][$i]
  2558. = $this->_getDataCellForNonNumericAndNonBlobColumns(
  2559. $row[$i], $class, $meta, $map, $_url_params,
  2560. $condition_field, $transformation_plugin,
  2561. $default_function, $transform_options,
  2562. $is_field_truncated, $analyzed_sql, $dt_result, $i
  2563. );
  2564. }
  2565. // output stored cell
  2566. if ($directionCondition) {
  2567. $row_values_html
  2568. .= $vertical_display['data'][$row_no][$i];
  2569. }
  2570. if (isset($vertical_display['rowdata'][$i][$row_no])) {
  2571. $vertical_display['rowdata'][$i][$row_no]
  2572. .= $vertical_display['data'][$row_no][$i];
  2573. } else {
  2574. $vertical_display['rowdata'][$i][$row_no]
  2575. = $vertical_display['data'][$row_no][$i];
  2576. }
  2577. $this->__set('vertical_display', $vertical_display);
  2578. } // end for
  2579. return $row_values_html;
  2580. } // end of the '_getRowValues()' function
  2581. /**
  2582. * Gather delete/edit url links for further outputs
  2583. *
  2584. * @param integer $row_no the index of current row
  2585. * @param array $is_display which elements to display
  2586. * @param string $where_clause where clause
  2587. * @param string $where_clause_html the html encoded where clause
  2588. * @param string $js_conf text for the JS confirmation
  2589. * @param string $del_url the url for delete row
  2590. * @param string $del_query the query for delete row
  2591. * @param string $del_str the label for delete row
  2592. * @param string $edit_anchor_class the class for html element for edit
  2593. * @param string $edit_url the url for edit row
  2594. * @param string $edit_str the label for edit row
  2595. * @param string $copy_url the url for copy row
  2596. * @param string $copy_str the label for copy row
  2597. * @param string $alternating_color_class class for display two colors in rows
  2598. * @param array $condition_array array of keys
  2599. * (primary,unique,condition)
  2600. *
  2601. * @return void
  2602. *
  2603. * @access private
  2604. *
  2605. * @see _getTableBody()
  2606. */
  2607. private function _gatherLinksForLaterOutputs(
  2608. $row_no, $is_display, $where_clause, $where_clause_html, $js_conf,
  2609. $del_url, $del_query, $del_str, $edit_anchor_class, $edit_url, $edit_str,
  2610. $copy_url, $copy_str, $alternating_color_class, $condition_array
  2611. ) {
  2612. $vertical_display = $this->__get('vertical_display');
  2613. if (! isset($vertical_display['edit'][$row_no])) {
  2614. $vertical_display['edit'][$row_no] = '';
  2615. $vertical_display['copy'][$row_no] = '';
  2616. $vertical_display['delete'][$row_no] = '';
  2617. $vertical_display['row_delete'][$row_no] = '';
  2618. }
  2619. $vertical_class = ' row_' . $row_no;
  2620. if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
  2621. $vertical_class .= ' vpointer';
  2622. }
  2623. if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
  2624. $vertical_class .= ' vmarker';
  2625. }
  2626. if (!empty($del_url)
  2627. && ($is_display['del_lnk'] != self::KILL_PROCESS)
  2628. ) {
  2629. $vertical_display['row_delete'][$row_no]
  2630. .= $this->_getCheckboxForMultiRowSubmissions(
  2631. $del_url, $is_display, $row_no, $where_clause_html,
  2632. $condition_array, $del_query, '[%_PMA_CHECKBOX_DIR_%]',
  2633. $alternating_color_class . $vertical_class
  2634. );
  2635. } else {
  2636. unset($vertical_display['row_delete'][$row_no]);
  2637. }
  2638. if (isset($edit_url)) {
  2639. $vertical_display['edit'][$row_no] .= $this->_getEditLink(
  2640. $edit_url,
  2641. $alternating_color_class . ' ' . $edit_anchor_class
  2642. . $vertical_class, $edit_str,
  2643. $where_clause,
  2644. $where_clause_html
  2645. );
  2646. } else {
  2647. unset($vertical_display['edit'][$row_no]);
  2648. }
  2649. if (isset($copy_url)) {
  2650. $vertical_display['copy'][$row_no] .= $this->_getCopyLink(
  2651. $copy_url, $copy_str, $where_clause, $where_clause_html,
  2652. $alternating_color_class . $vertical_class
  2653. );
  2654. } else {
  2655. unset($vertical_display['copy'][$row_no]);
  2656. }
  2657. if (isset($del_url)) {
  2658. if (! isset($js_conf)) {
  2659. $js_conf = '';
  2660. }
  2661. $vertical_display['delete'][$row_no]
  2662. .= $this->_getDeleteLink(
  2663. $del_url, $del_str, $js_conf,
  2664. $alternating_color_class . $vertical_class
  2665. );
  2666. } else {
  2667. unset($vertical_display['delete'][$row_no]);
  2668. }
  2669. $this->__set('vertical_display', $vertical_display);
  2670. } // end of the '_gatherLinksForLaterOutputs()' function
  2671. /**
  2672. * Get link for display special schema links
  2673. *
  2674. * @param string $column_value column value
  2675. * @param array $row_info information about row
  2676. * @param string $field_name column name
  2677. *
  2678. * @return string generated link
  2679. */
  2680. private function _getSpecialLinkUrl($column_value, $row_info, $field_name)
  2681. {
  2682. $linking_url_params = array();
  2683. $link_relations = $GLOBALS['special_schema_links']
  2684. [strtolower($this->__get('db'))]
  2685. [strtolower($this->__get('table'))]
  2686. [$field_name];
  2687. if (! is_array($link_relations['link_param'])) {
  2688. $linking_url_params[$link_relations['link_param']] = $column_value;
  2689. } else {
  2690. // Consider only the case of creating link for column field
  2691. // sql query that needs to be passed as url param
  2692. $sql = 'SELECT `' . $column_value . '` FROM `'
  2693. . $row_info[$link_relations['link_param'][1]] . '`.`'
  2694. . $row_info[$link_relations['link_param'][2]] . '`';
  2695. $linking_url_params[$link_relations['link_param'][0]] = $sql;
  2696. }
  2697. if (! empty($link_relations['link_dependancy_params'])) {
  2698. foreach ($link_relations['link_dependancy_params'] as $new_param) {
  2699. // If param_info is an array, set the key and value
  2700. // from that array
  2701. if (is_array($new_param['param_info'])) {
  2702. $linking_url_params[$new_param['param_info'][0]]
  2703. = $new_param['param_info'][1];
  2704. } else {
  2705. $linking_url_params[$new_param['param_info']]
  2706. = $row_info[strtolower($new_param['column_name'])];
  2707. // Special case 1 - when executing routines, according
  2708. // to the type of the routine, url param changes
  2709. if (!empty($row_info['routine_type'])) {
  2710. $lowerRoutineType = strtolower($row_info['routine_type']);
  2711. if ($lowerRoutineType == self::ROUTINE_PROCEDURE
  2712. || $lowerRoutineType == self::ROUTINE_FUNCTION
  2713. ) {
  2714. $linking_url_params['edit_item'] = 1;
  2715. }
  2716. }
  2717. }
  2718. }
  2719. }
  2720. return $link_relations['default_page']
  2721. . PMA_URL_getCommon($linking_url_params);
  2722. }
  2723. /**
  2724. * Prepare row information for display special links
  2725. *
  2726. * @param array $row current row data
  2727. * @param array $col_order the column order
  2728. *
  2729. * @return array $row_info associative array with column nama -> value
  2730. */
  2731. private function _getRowInfoForSpecialLinks($row, $col_order)
  2732. {
  2733. $row_info = array();
  2734. $fields_meta = $this->__get('fields_meta');
  2735. for ($n = 0; $n < $this->__get('fields_cnt'); ++$n) {
  2736. $m = $col_order ? $col_order[$n] : $n;
  2737. $row_info[strtolower($fields_meta[$m]->name)] = $row[$m];
  2738. }
  2739. return $row_info;
  2740. }
  2741. /**
  2742. * Get url sql query without conditions to shorten URLs
  2743. *
  2744. * @param array $analyzed_sql analyzed query
  2745. *
  2746. * @return string $url_sql analyzed sql query
  2747. *
  2748. * @access private
  2749. *
  2750. * @see _getTableBody()
  2751. */
  2752. private function _getUrlSqlQuery($analyzed_sql)
  2753. {
  2754. if (isset($analyzed_sql)
  2755. && isset($analyzed_sql[0])
  2756. && isset($analyzed_sql[0]['querytype'])
  2757. && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT)
  2758. && (strlen($this->__get('sql_query')) > 200)
  2759. ) {
  2760. $url_sql_query = 'SELECT ';
  2761. if (isset($analyzed_sql[0]['queryflags']['distinct'])) {
  2762. $url_sql_query .= ' DISTINCT ';
  2763. }
  2764. $url_sql_query .= $analyzed_sql[0]['select_expr_clause'];
  2765. if (!empty($analyzed_sql[0]['from_clause'])) {
  2766. $url_sql_query .= ' FROM ' . $analyzed_sql[0]['from_clause'];
  2767. }
  2768. return $url_sql_query;
  2769. }
  2770. return $this->__get('sql_query');
  2771. } // end of the '_getUrlSqlQuery()' function
  2772. /**
  2773. * Get column order and column visibility
  2774. *
  2775. * @param array $analyzed_sql the analyzed query
  2776. *
  2777. * @return array 2 element array - $col_order, $col_visib
  2778. *
  2779. * @access private
  2780. *
  2781. * @see _getTableBody()
  2782. */
  2783. private function _getColumnParams($analyzed_sql)
  2784. {
  2785. if ($this->_isSelect($analyzed_sql)) {
  2786. $pmatable = new PMA_Table($this->__get('table'), $this->__get('db'));
  2787. $col_order = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_ORDER);
  2788. $col_visib = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_VISIB);
  2789. } else {
  2790. $col_order = false;
  2791. $col_visib = false;
  2792. }
  2793. return array($col_order, $col_visib);
  2794. } // end of the '_getColumnParams()' function
  2795. /**
  2796. * Prepare vertical display mode necessay HTML stuff
  2797. *
  2798. * @param array $vertical_display informations used with vertical
  2799. * display mode
  2800. * @param integer $row_no the index of current row
  2801. * @param boolean $directionCondition the directional condition
  2802. *
  2803. * @return string $vertical_disp_html html content
  2804. *
  2805. * @access private
  2806. *
  2807. * @see _getTableBody()
  2808. */
  2809. private function _getVerticalDisplaySupportSegments(
  2810. $vertical_display, $row_no, $directionCondition
  2811. ) {
  2812. $support_html = '';
  2813. if ((($row_no != 0) && ($_SESSION['tmpval']['repeat_cells'] != 0))
  2814. && !($row_no % $_SESSION['tmpval']['repeat_cells'])
  2815. && $directionCondition
  2816. ) {
  2817. $support_html .= '<tr>' . "\n";
  2818. if ($vertical_display['emptypre'] > 0) {
  2819. $support_html .= ' <th colspan="'
  2820. . $vertical_display['emptypre'] . '">'
  2821. . "\n" . ' &nbsp;</th>' . "\n";
  2822. } else if ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) {
  2823. $support_html .= ' <th></th>' . "\n";
  2824. }
  2825. foreach ($vertical_display['desc'] as $val) {
  2826. $support_html .= $val;
  2827. }
  2828. if ($vertical_display['emptyafter'] > 0) {
  2829. $support_html
  2830. .= ' <th colspan="' . $vertical_display['emptyafter']
  2831. . '">'
  2832. . "\n" . ' &nbsp;</th>' . "\n";
  2833. }
  2834. $support_html .= '</tr>' . "\n";
  2835. } // end if
  2836. return $support_html;
  2837. } // end of the '_getVerticalDisplaySupportSegments()' function
  2838. /**
  2839. * Get modified links
  2840. *
  2841. * @param string $where_clause the where clause of the sql
  2842. * @param boolean $clause_is_unique the unique condition of clause
  2843. * @param string $url_sql_query the analyzed sql query
  2844. *
  2845. * @return array 5 element array - $edit_url, $copy_url,
  2846. * $edit_str, $copy_str, $edit_anchor_class
  2847. *
  2848. * @access private
  2849. *
  2850. * @see _getTableBody()
  2851. */
  2852. private function _getModifiedLinks(
  2853. $where_clause, $clause_is_unique, $url_sql_query
  2854. ) {
  2855. $_url_params = array(
  2856. 'db' => $this->__get('db'),
  2857. 'table' => $this->__get('table'),
  2858. 'where_clause' => $where_clause,
  2859. 'clause_is_unique' => $clause_is_unique,
  2860. 'sql_query' => $url_sql_query,
  2861. 'goto' => 'sql.php',
  2862. );
  2863. $edit_url = 'tbl_change.php'
  2864. . PMA_URL_getCommon(
  2865. $_url_params + array('default_action' => 'update')
  2866. );
  2867. $copy_url = 'tbl_change.php'
  2868. . PMA_URL_getCommon(
  2869. $_url_params + array('default_action' => 'insert')
  2870. );
  2871. $edit_str = $this->_getActionLinkContent(
  2872. 'b_edit.png', __('Edit')
  2873. );
  2874. $copy_str = $this->_getActionLinkContent(
  2875. 'b_insrow.png', __('Copy')
  2876. );
  2877. // Class definitions required for grid editing jQuery scripts
  2878. $edit_anchor_class = "edit_row_anchor";
  2879. if ( $clause_is_unique == 0) {
  2880. $edit_anchor_class .= ' nonunique';
  2881. }
  2882. return array($edit_url, $copy_url, $edit_str, $copy_str, $edit_anchor_class);
  2883. } // end of the '_getModifiedLinks()' function
  2884. /**
  2885. * Get delete and kill links
  2886. *
  2887. * @param string $where_clause the where clause of the sql
  2888. * @param boolean $clause_is_unique the unique condition of clause
  2889. * @param string $url_sql_query the analyzed sql query
  2890. * @param string $del_lnk the delete link of current row
  2891. * @param array $row the current row
  2892. *
  2893. * @return array 4 element array - $del_query,
  2894. * $del_url, $del_str, $js_conf
  2895. *
  2896. * @access private
  2897. *
  2898. * @see _getTableBody()
  2899. */
  2900. private function _getDeleteAndKillLinks(
  2901. $where_clause, $clause_is_unique, $url_sql_query, $del_lnk, $row
  2902. ) {
  2903. $goto = $this->__get('goto');
  2904. if ($del_lnk == self::DELETE_ROW) { // delete row case
  2905. $_url_params = array(
  2906. 'db' => $this->__get('db'),
  2907. 'table' => $this->__get('table'),
  2908. 'sql_query' => $url_sql_query,
  2909. 'message_to_show' => __('The row has been deleted.'),
  2910. 'goto' => (empty($goto) ? 'tbl_sql.php' : $goto),
  2911. );
  2912. $lnk_goto = 'sql.php' . PMA_URL_getCommon($_url_params, 'text');
  2913. $del_query = 'DELETE FROM '
  2914. . PMA_Util::backquote($this->__get('db')) . '.'
  2915. . PMA_Util::backquote($this->__get('table'))
  2916. . ' WHERE ' . $where_clause .
  2917. ($clause_is_unique ? '' : ' LIMIT 1');
  2918. $_url_params = array(
  2919. 'db' => $this->__get('db'),
  2920. 'table' => $this->__get('table'),
  2921. 'sql_query' => $del_query,
  2922. 'message_to_show' => __('The row has been deleted.'),
  2923. 'goto' => $lnk_goto,
  2924. );
  2925. $del_url = 'sql.php' . PMA_URL_getCommon($_url_params);
  2926. $js_conf = 'DELETE FROM ' . PMA_jsFormat($this->__get('db')) . '.'
  2927. . PMA_jsFormat($this->__get('table'))
  2928. . ' WHERE ' . PMA_jsFormat($where_clause, false)
  2929. . ($clause_is_unique ? '' : ' LIMIT 1');
  2930. $del_str = $this->_getActionLinkContent('b_drop.png', __('Delete'));
  2931. } elseif ($del_lnk == self::KILL_PROCESS) { // kill process case
  2932. $_url_params = array(
  2933. 'db' => $this->__get('db'),
  2934. 'table' => $this->__get('table'),
  2935. 'sql_query' => $url_sql_query,
  2936. 'goto' => 'index.php',
  2937. );
  2938. $lnk_goto = 'sql.php'
  2939. . PMA_URL_getCommon(
  2940. $_url_params, 'text'
  2941. );
  2942. $_url_params = array(
  2943. 'db' => 'mysql',
  2944. 'sql_query' => 'KILL ' . $row[0],
  2945. 'goto' => $lnk_goto,
  2946. );
  2947. $del_url = 'sql.php' . PMA_URL_getCommon($_url_params);
  2948. $del_query = 'KILL ' . $row[0];
  2949. $js_conf = 'KILL ' . $row[0];
  2950. $del_str = PMA_Util::getIcon(
  2951. 'b_drop.png', __('Kill')
  2952. );
  2953. }
  2954. return array($del_query, $del_url, $del_str, $js_conf);
  2955. } // end of the '_getDeleteAndKillLinks()' function
  2956. /**
  2957. * Get content inside the table row action links (Edit/Copy/Delete)
  2958. *
  2959. * @param string $icon The name of the file to get
  2960. * @param string $display_text The text displaying after the image icon
  2961. *
  2962. * @return string
  2963. *
  2964. * @access private
  2965. *
  2966. * @see _getModifiedLinks(), _getDeleteAndKillLinks()
  2967. */
  2968. private function _getActionLinkContent($icon, $display_text)
  2969. {
  2970. $linkContent = '';
  2971. if (isset($GLOBALS['cfg']['RowActionType'])
  2972. && $GLOBALS['cfg']['RowActionType'] == self::ACTION_LINK_CONTENT_ICONS
  2973. ) {
  2974. $linkContent .= '<span class="nowrap">'
  2975. . PMA_Util::getImage(
  2976. $icon, $display_text
  2977. )
  2978. . '</span>';
  2979. } else if (isset($GLOBALS['cfg']['RowActionType'])
  2980. && $GLOBALS['cfg']['RowActionType'] == self::ACTION_LINK_CONTENT_TEXT
  2981. ) {
  2982. $linkContent .= '<span class="nowrap">' . $display_text . '</span>';
  2983. } else {
  2984. $linkContent .= PMA_Util::getIcon(
  2985. $icon, $display_text
  2986. );
  2987. }
  2988. return $linkContent;
  2989. }
  2990. /**
  2991. * Prepare placed links
  2992. *
  2993. * @param string $dir the direction of links should place
  2994. * @param string $del_url the url for delete row
  2995. * @param array $is_display which elements to display
  2996. * @param integer $row_no the index of current row
  2997. * @param string $where_clause the where clause of the sql
  2998. * @param string $where_clause_html the html encoded where clause
  2999. * @param array $condition_array array of keys (primary, unique, condition)
  3000. * @param string $del_query the query for delete row
  3001. * @param string $dir_letter the letter denoted the direction
  3002. * @param string $edit_url the url for edit row
  3003. * @param string $copy_url the url for copy row
  3004. * @param string $edit_anchor_class the class for html element for edit
  3005. * @param string $edit_str the label for edit row
  3006. * @param string $copy_str the label for copy row
  3007. * @param string $del_str the label for delete row
  3008. * @param string $js_conf text for the JS confirmation
  3009. *
  3010. * @return string html content
  3011. *
  3012. * @access private
  3013. *
  3014. * @see _getTableBody()
  3015. */
  3016. private function _getPlacedLinks(
  3017. $dir, $del_url, $is_display, $row_no, $where_clause, $where_clause_html,
  3018. $condition_array, $del_query, $dir_letter, $edit_url, $copy_url,
  3019. $edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf
  3020. ) {
  3021. if (! isset($js_conf)) {
  3022. $js_conf = '';
  3023. }
  3024. return $this->_getCheckboxAndLinks(
  3025. $dir, $del_url, $is_display,
  3026. $row_no, $where_clause, $where_clause_html, $condition_array,
  3027. $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class,
  3028. $edit_str, $copy_str, $del_str, $js_conf
  3029. );
  3030. } // end of the '_getPlacedLinks()' function
  3031. /**
  3032. * Get the combined classes for a column
  3033. *
  3034. * @param string $grid_edit_class the class for all editable columns
  3035. * @param string $not_null_class the class for not null columns
  3036. * @param string $relation_class the class for relations in a column
  3037. * @param string $hide_class the class for visibility of a column
  3038. * @param string $field_type_class the class related to type of the field
  3039. * @param integer $row_no the row index
  3040. *
  3041. * @return string $class the combined classes
  3042. *
  3043. * @access private
  3044. *
  3045. * @see _getTableBody()
  3046. */
  3047. private function _getClassesForColumn(
  3048. $grid_edit_class, $not_null_class, $relation_class,
  3049. $hide_class, $field_type_class, $row_no
  3050. ) {
  3051. $printview = $this->__get('printview');
  3052. $class = 'data ' . $grid_edit_class . ' ' . $not_null_class . ' '
  3053. . $relation_class . ' ' . $hide_class . ' ' . $field_type_class;
  3054. $disp_direction = $_SESSION['tmpval']['disp_direction'];
  3055. if (($disp_direction == self::DISP_DIR_VERTICAL)
  3056. && (! isset($printview) || ($printview != '1'))
  3057. ) {
  3058. // the row number corresponds to a data row, not HTML table row
  3059. $class .= ' row_' . $row_no;
  3060. if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
  3061. $class .= ' vpointer';
  3062. }
  3063. if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
  3064. $class .= ' vmarker';
  3065. }
  3066. }
  3067. return $class;
  3068. } // end of the '_getClassesForColumn()' function
  3069. /**
  3070. * Get class for datetime related fields
  3071. *
  3072. * @param string $type the type of the column field
  3073. *
  3074. * @return string $field_type_class the class for the column
  3075. *
  3076. * @access private
  3077. *
  3078. * @see _getTableBody()
  3079. */
  3080. private function _getClassForDateTimeRelatedFields($type)
  3081. {
  3082. if ((substr($type, 0, 9) == self::TIMESTAMP_FIELD)
  3083. || ($type == self::DATETIME_FIELD)
  3084. ) {
  3085. $field_type_class = 'datetimefield';
  3086. } elseif ($type == self::DATE_FIELD) {
  3087. $field_type_class = 'datefield';
  3088. } elseif ($type == self::TIME_FIELD) {
  3089. $field_type_class = 'timefield';
  3090. } else {
  3091. $field_type_class = '';
  3092. }
  3093. return $field_type_class;
  3094. } // end of the '_getClassForDateTimeRelatedFields()' function
  3095. /**
  3096. * Prepare data cell for numeric type fields
  3097. *
  3098. * @param string $column the relevant column in data row
  3099. * @param string $class the html class for column
  3100. * @param boolean $condition_field the column should highlighted
  3101. * or not
  3102. * @param object $meta the meta-information about this
  3103. * field
  3104. * @param array $map the list of relations
  3105. * @param boolean $is_field_truncated the condition for blob data
  3106. * replacements
  3107. * @param array $analyzed_sql the analyzed query
  3108. * @param string $transformation_plugin the name of transformation plugin
  3109. * @param string $default_function the default transformation function
  3110. * @param array $transform_options the transformation parameters
  3111. *
  3112. * @return string $cell the prepared cell, html content
  3113. *
  3114. * @access private
  3115. *
  3116. * @see _getTableBody()
  3117. */
  3118. private function _getDataCellForNumericColumns(
  3119. $column, $class, $condition_field, $meta, $map, $is_field_truncated,
  3120. $analyzed_sql, $transformation_plugin, $default_function,
  3121. $transform_options
  3122. ) {
  3123. if (! isset($column) || is_null($column)) {
  3124. $cell = $this->_buildNullDisplay(
  3125. 'right ' . $class, $condition_field, $meta, ''
  3126. );
  3127. } elseif ($column != '') {
  3128. $nowrap = ' nowrap';
  3129. $where_comparison = ' = ' . $column;
  3130. $cell = $this->_getRowData(
  3131. 'right ' . $class, $condition_field,
  3132. $analyzed_sql, $meta, $map, $column,
  3133. $transformation_plugin, $default_function, $nowrap,
  3134. $where_comparison, $transform_options,
  3135. $is_field_truncated
  3136. );
  3137. } else {
  3138. $cell = $this->_buildEmptyDisplay(
  3139. 'right ' . $class, $condition_field, $meta, ''
  3140. );
  3141. }
  3142. return $cell;
  3143. } // end of the '_getDataCellForNumericColumns()' function
  3144. /**
  3145. * Get data cell for blob type fields
  3146. *
  3147. * @param string $column the relevant column in data row
  3148. * @param string $class the html class for column
  3149. * @param object $meta the meta-information about this
  3150. * field
  3151. * @param array $_url_params the parameters for generate url
  3152. * @param string $field_flags field flags for column(blob,
  3153. * primary etc)
  3154. * @param string $transformation_plugin the name of transformation function
  3155. * @param string $default_function the default transformation function
  3156. * @param array $transform_options the transformation parameters
  3157. * @param boolean $condition_field the column should highlighted
  3158. * or not
  3159. * @param boolean $is_field_truncated the condition for blob data
  3160. * replacements
  3161. *
  3162. * @return string $cell the prepared cell, html content
  3163. *
  3164. * @access private
  3165. *
  3166. * @see _getTableBody()
  3167. */
  3168. private function _getDataCellForBlobColumns(
  3169. $column, $class, $meta, $_url_params, $field_flags, $transformation_plugin,
  3170. $default_function, $transform_options, $condition_field, $is_field_truncated
  3171. ) {
  3172. if (stristr($field_flags, self::BINARY_FIELD)) {
  3173. // remove 'grid_edit' from $class as we can't edit binary data.
  3174. $class = str_replace('grid_edit', '', $class);
  3175. if (! isset($column) || is_null($column)) {
  3176. $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
  3177. } else {
  3178. $blobtext = $this->_handleNonPrintableContents(
  3179. self::BLOB_FIELD, (isset($column) ? $column : ''),
  3180. $transformation_plugin, $transform_options,
  3181. $default_function, $meta, $_url_params
  3182. );
  3183. $cell = $this->_buildValueDisplay(
  3184. $class, $condition_field, $blobtext
  3185. );
  3186. unset($blobtext);
  3187. }
  3188. } else {
  3189. // not binary:
  3190. if (! isset($column) || is_null($column)) {
  3191. $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
  3192. } elseif ($column != '') {
  3193. // if a transform function for blob is set, none of these
  3194. // replacements will be made
  3195. $limitChars = $GLOBALS['cfg']['LimitChars'];
  3196. if (($GLOBALS['PMA_String']->strlen($column) > $limitChars)
  3197. && ($_SESSION['tmpval']['pftext'] == self::DISPLAY_PARTIAL_TEXT)
  3198. && empty($this->transformation_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower(strtolower($meta->name))])
  3199. ) {
  3200. $column = $GLOBALS['PMA_String']->substr(
  3201. $column, 0, $GLOBALS['cfg']['LimitChars']
  3202. ) . '...';
  3203. $is_field_truncated = true;
  3204. }
  3205. // displays all space characters, 4 space
  3206. // characters for tabulations and <cr>/<lf>
  3207. $column = ($default_function != $transformation_plugin)
  3208. ? $transformation_plugin->applyTransformation(
  3209. $column,
  3210. $transform_options,
  3211. $meta
  3212. )
  3213. : $this->$default_function($column, array(), $meta);
  3214. if ($is_field_truncated) {
  3215. $class .= ' truncated';
  3216. }
  3217. $cell = $this->_buildValueDisplay($class, $condition_field, $column);
  3218. } else {
  3219. $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
  3220. }
  3221. }
  3222. return $cell;
  3223. } // end of the '_getDataCellForBlobColumns()' function
  3224. /**
  3225. * Get data cell for geometry type fields
  3226. *
  3227. * @param string $column the relevant column in data row
  3228. * @param string $class the html class for column
  3229. * @param object $meta the meta-information about this field
  3230. * @param array $map the list of relations
  3231. * @param array $_url_params the parameters for generate url
  3232. * @param boolean $condition_field the column should highlighted or not
  3233. * @param string $transformation_plugin the name of transformation function
  3234. * @param string $default_function the default transformation function
  3235. * @param array $transform_options the transformation parameters
  3236. * @param boolean $is_field_truncated the condition for blob data replacements
  3237. * @param array $analyzed_sql the analyzed query
  3238. *
  3239. * @return string $cell the prepared data cell, html content
  3240. *
  3241. * @access private
  3242. *
  3243. * @see _getTableBody()
  3244. */
  3245. private function _getDataCellForGeometryColumns(
  3246. $column, $class, $meta, $map, $_url_params, $condition_field,
  3247. $transformation_plugin, $default_function, $transform_options,
  3248. $is_field_truncated, $analyzed_sql
  3249. ) {
  3250. $pftext = $_SESSION['tmpval']['pftext'];
  3251. $limitChars = $GLOBALS['cfg']['LimitChars'];
  3252. if (! isset($column) || is_null($column)) {
  3253. $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
  3254. } elseif ($column != '') {
  3255. // Display as [GEOMETRY - (size)]
  3256. if ($_SESSION['tmpval']['geoOption'] == self::GEOMETRY_DISP_GEOM) {
  3257. $geometry_text = $this->_handleNonPrintableContents(
  3258. strtoupper(self::GEOMETRY_FIELD),
  3259. (isset($column) ? $column : ''), $transformation_plugin,
  3260. $transform_options, $default_function, $meta
  3261. );
  3262. $cell = $this->_buildValueDisplay(
  3263. $class, $condition_field, $geometry_text
  3264. );
  3265. } elseif ($_SESSION['tmpval']['geoOption'] == self::GEOMETRY_DISP_WKT) {
  3266. // Prepare in Well Known Text(WKT) format.
  3267. $where_comparison = ' = ' . $column;
  3268. // Convert to WKT format
  3269. $wktval = PMA_Util::asWKT($column);
  3270. if (($GLOBALS['PMA_String']->strlen($wktval) > $limitChars)
  3271. && ($pftext == self::DISPLAY_PARTIAL_TEXT)
  3272. ) {
  3273. $wktval = $GLOBALS['PMA_String']->substr(
  3274. $wktval, 0, $limitChars
  3275. ) . '...';
  3276. $is_field_truncated = true;
  3277. }
  3278. $cell = $this->_getRowData(
  3279. $class, $condition_field, $analyzed_sql, $meta, $map,
  3280. $wktval, $transformation_plugin, $default_function, '',
  3281. $where_comparison, $transform_options,
  3282. $is_field_truncated
  3283. );
  3284. } else {
  3285. // Prepare in Well Known Binary (WKB) format.
  3286. if ($_SESSION['tmpval']['display_binary']) {
  3287. $where_comparison = ' = ' . $column;
  3288. $wkbval = $this->_displayBinaryAsPrintable($column, 'binary', 8);
  3289. if (($GLOBALS['PMA_String']->strlen($wkbval) > $limitChars)
  3290. && ($pftext == self::DISPLAY_PARTIAL_TEXT)
  3291. ) {
  3292. $wkbval = $GLOBALS['PMA_String']->substr(
  3293. $wkbval, 0, $GLOBALS['cfg']['LimitChars']
  3294. ) . '...';
  3295. $is_field_truncated = true;
  3296. }
  3297. $cell = $this->_getRowData(
  3298. $class, $condition_field,
  3299. $analyzed_sql, $meta, $map, $wkbval,
  3300. $transformation_plugin, $default_function, '',
  3301. $where_comparison, $transform_options,
  3302. $is_field_truncated
  3303. );
  3304. } else {
  3305. $wkbval = $this->_handleNonPrintableContents(
  3306. self::BINARY_FIELD, $column, $transformation_plugin,
  3307. $transform_options, $default_function, $meta,
  3308. $_url_params
  3309. );
  3310. $cell = $this->_buildValueDisplay(
  3311. $class, $condition_field, $wkbval
  3312. );
  3313. }
  3314. }
  3315. } else {
  3316. $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
  3317. }
  3318. return $cell;
  3319. } // end of the '_getDataCellForGeometryColumns()' function
  3320. /**
  3321. * Get data cell for non numeric and non blob type fields
  3322. *
  3323. * @param string $column the relevant column in data row
  3324. * @param string $class the html class for column
  3325. * @param object $meta the meta-information about the field
  3326. * @param array $map the list of relations
  3327. * @param array $_url_params the parameters for generate url
  3328. * @param boolean $condition_field the column should highlighted
  3329. * or not
  3330. * @param string $transformation_plugin the name of transformation function
  3331. * @param string $default_function the default transformation function
  3332. * @param array $transform_options the transformation parameters
  3333. * @param boolean $is_field_truncated the condition for blob data
  3334. * replacements
  3335. * @param array $analyzed_sql the analyzed query
  3336. * @param integer &$dt_result the link id associated to the query
  3337. * which results have to be displayed
  3338. * @param integer $col_index the column index
  3339. *
  3340. * @return string $cell the prepared data cell, html content
  3341. *
  3342. * @access private
  3343. *
  3344. * @see _getTableBody()
  3345. */
  3346. private function _getDataCellForNonNumericAndNonBlobColumns(
  3347. $column, $class, $meta, $map, $_url_params, $condition_field,
  3348. $transformation_plugin, $default_function, $transform_options,
  3349. $is_field_truncated, $analyzed_sql, &$dt_result, $col_index
  3350. ) {
  3351. $limitChars = $GLOBALS['cfg']['LimitChars'];
  3352. $is_analyse = $this->__get('is_analyse');
  3353. $field_flags = $GLOBALS['dbi']->fieldFlags($dt_result, $col_index);
  3354. if (stristr($field_flags, self::BINARY_FIELD)
  3355. && ($GLOBALS['cfg']['ProtectBinary'] == 'all'
  3356. || $GLOBALS['cfg']['ProtectBinary'] == 'noblob')
  3357. ) {
  3358. $class = str_replace('grid_edit', '', $class);
  3359. }
  3360. if (! isset($column) || is_null($column)) {
  3361. $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
  3362. } elseif ($column != '') {
  3363. // Cut all fields to $GLOBALS['cfg']['LimitChars']
  3364. // (unless it's a link-type transformation)
  3365. if ($GLOBALS['PMA_String']->strlen($column) > $limitChars
  3366. && ($_SESSION['tmpval']['pftext'] == self::DISPLAY_PARTIAL_TEXT)
  3367. && ! (gettype($transformation_plugin) == "object"
  3368. && strpos($transformation_plugin->getName(), 'Link') !== false)
  3369. ) {
  3370. $column = $GLOBALS['PMA_String']->substr(
  3371. $column, 0, $GLOBALS['cfg']['LimitChars']
  3372. ) . '...';
  3373. $is_field_truncated = true;
  3374. }
  3375. $formatted = false;
  3376. if (isset($meta->_type) && $meta->_type === MYSQLI_TYPE_BIT) {
  3377. $column = PMA_Util::printableBitValue(
  3378. $column, $meta->length
  3379. );
  3380. // some results of PROCEDURE ANALYSE() are reported as
  3381. // being BINARY but they are quite readable,
  3382. // so don't treat them as BINARY
  3383. } elseif (stristr($field_flags, self::BINARY_FIELD)
  3384. && ($meta->type == self::STRING_FIELD)
  3385. && !(isset($is_analyse) && $is_analyse)
  3386. ) {
  3387. if ($_SESSION['tmpval']['display_binary']) {
  3388. // user asked to see the real contents of BINARY
  3389. // fields
  3390. $column = $this->_displayBinaryAsPrintable($column, 'binary');
  3391. } else {
  3392. // we show the BINARY message and field's size
  3393. // (or maybe use a transformation)
  3394. $column = $this->_handleNonPrintableContents(
  3395. self::BINARY_FIELD, $column, $transformation_plugin,
  3396. $transform_options, $default_function,
  3397. $meta, $_url_params
  3398. );
  3399. $formatted = true;
  3400. }
  3401. } elseif (((substr($meta->type, 0, 9) == self::TIMESTAMP_FIELD)
  3402. || ($meta->type == self::DATETIME_FIELD)
  3403. || ($meta->type == self::TIME_FIELD)
  3404. || ($meta->type == self::TIME_FIELD))
  3405. && (strpos($column, ".") === true)
  3406. ) {
  3407. $column = PMA_Util::addMicroseconds($column);
  3408. }
  3409. if ($formatted) {
  3410. $cell = $this->_buildValueDisplay(
  3411. $class, $condition_field, $column
  3412. );
  3413. } else {
  3414. // transform functions may enable no-wrapping:
  3415. $function_nowrap = 'applyTransformationNoWrap';
  3416. $bool_nowrap = (($default_function != $transformation_plugin)
  3417. && function_exists($transformation_plugin->$function_nowrap()))
  3418. ? $transformation_plugin->$function_nowrap($transform_options)
  3419. : false;
  3420. // do not wrap if date field type
  3421. $nowrap = (preg_match('@DATE|TIME@i', $meta->type)
  3422. || $bool_nowrap) ? ' nowrap' : '';
  3423. $where_comparison = ' = \''
  3424. . PMA_Util::sqlAddSlashes($column)
  3425. . '\'';
  3426. $cell = $this->_getRowData(
  3427. $class, $condition_field,
  3428. $analyzed_sql, $meta, $map, $column,
  3429. $transformation_plugin, $default_function, $nowrap,
  3430. $where_comparison, $transform_options,
  3431. $is_field_truncated
  3432. );
  3433. }
  3434. } else {
  3435. $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
  3436. }
  3437. return $cell;
  3438. } // end of the '_getDataCellForNonNumericAndNonBlobColumns()' function
  3439. /**
  3440. * Get the resulted table with the vertical direction mode.
  3441. *
  3442. * @param array $analyzed_sql the analyzed query
  3443. * @param array $is_display display mode
  3444. *
  3445. * @return string html content
  3446. *
  3447. * @access private
  3448. *
  3449. * @see _getTable()
  3450. */
  3451. private function _getVerticalTable($analyzed_sql, $is_display)
  3452. {
  3453. $vertical_table_html = '';
  3454. $vertical_display = $this->__get('vertical_display');
  3455. // Prepares "multi row delete" link at top if required
  3456. if (($GLOBALS['cfg']['RowActionLinks'] != self::POSITION_RIGHT)
  3457. && is_array($vertical_display['row_delete'])
  3458. && ((count($vertical_display['row_delete']) > 0)
  3459. || !empty($vertical_display['textbtn']))
  3460. ) {
  3461. $vertical_table_html .= '<tr>' . "\n";
  3462. if ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) {
  3463. // if we are not showing the RowActionLinks, then we need to show
  3464. // the Multi-Row-Action checkboxes
  3465. $vertical_table_html .= '<th></th>' . "\n";
  3466. }
  3467. $vertical_table_html .= $vertical_display['textbtn']
  3468. . $this->_getCheckBoxesForMultipleRowOperations('_left', $is_display)
  3469. . '</tr>' . "\n";
  3470. } // end if
  3471. // Prepares "edit" link at top if required
  3472. if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
  3473. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  3474. && is_array($vertical_display['edit'])
  3475. && ((count($vertical_display['edit']) > 0)
  3476. || !empty($vertical_display['textbtn']))
  3477. ) {
  3478. $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
  3479. 'edit'
  3480. );
  3481. } // end if
  3482. // Prepares "copy" link at top if required
  3483. if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
  3484. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  3485. && is_array($vertical_display['copy'])
  3486. && ((count($vertical_display['copy']) > 0)
  3487. || !empty($vertical_display['textbtn']))
  3488. ) {
  3489. $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
  3490. 'copy'
  3491. );
  3492. } // end if
  3493. // Prepares "delete" link at top if required
  3494. if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
  3495. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  3496. && is_array($vertical_display['delete'])
  3497. && ((count($vertical_display['delete']) > 0)
  3498. || !empty($vertical_display['textbtn']))
  3499. ) {
  3500. $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
  3501. 'delete'
  3502. );
  3503. } // end if
  3504. list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql);
  3505. // Prepares data
  3506. foreach ($vertical_display['desc'] as $j => $val) {
  3507. // assign appropriate key with current column order
  3508. $key = $col_order ? $col_order[$j] : $j;
  3509. $vertical_table_html .= '<tr'
  3510. . (($col_visib && !$col_visib[$j]) ? ' class="hide"' : '')
  3511. . '>' . "\n"
  3512. . $val;
  3513. $cell_displayed = 0;
  3514. foreach ($vertical_display['rowdata'][$key] as $subval) {
  3515. if (($cell_displayed != 0)
  3516. && ($_SESSION['tmpval']['repeat_cells'] != 0)
  3517. && ! ($cell_displayed % $_SESSION['tmpval']['repeat_cells'])
  3518. ) {
  3519. $vertical_table_html .= $val;
  3520. }
  3521. $vertical_table_html .= $subval;
  3522. $cell_displayed++;
  3523. } // end while
  3524. $vertical_table_html .= '</tr>' . "\n";
  3525. } // end while
  3526. // Prepares "multi row delete" link at bottom if required
  3527. if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
  3528. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  3529. && is_array($vertical_display['row_delete'])
  3530. && ((count($vertical_display['row_delete']) > 0)
  3531. || !empty($vertical_display['textbtn']))
  3532. ) {
  3533. $vertical_table_html .= '<tr>' . "\n"
  3534. . $vertical_display['textbtn']
  3535. . $this->_getCheckBoxesForMultipleRowOperations(
  3536. '_right', $is_display
  3537. )
  3538. . '</tr>' . "\n";
  3539. } // end if
  3540. // Prepares "edit" link at bottom if required
  3541. if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
  3542. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  3543. && is_array($vertical_display['edit'])
  3544. && ((count($vertical_display['edit']) > 0)
  3545. || !empty($vertical_display['textbtn']))
  3546. ) {
  3547. $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
  3548. 'edit'
  3549. );
  3550. } // end if
  3551. // Prepares "copy" link at bottom if required
  3552. if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
  3553. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  3554. && is_array($vertical_display['copy'])
  3555. && ((count($vertical_display['copy']) > 0)
  3556. || !empty($vertical_display['textbtn']))
  3557. ) {
  3558. $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
  3559. 'copy'
  3560. );
  3561. } // end if
  3562. // Prepares "delete" link at bottom if required
  3563. if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
  3564. || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
  3565. && is_array($vertical_display['delete'])
  3566. && ((count($vertical_display['delete']) > 0)
  3567. || !empty($vertical_display['textbtn']))
  3568. ) {
  3569. $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
  3570. 'delete'
  3571. );
  3572. }
  3573. return $vertical_table_html;
  3574. } // end of the '_getVerticalTable' function
  3575. /**
  3576. * Prepare edit, copy and delete links for verticle table
  3577. *
  3578. * @param string $operation edit/copy/delete
  3579. *
  3580. * @return string $links_html html content
  3581. *
  3582. * @access private
  3583. *
  3584. * @see _getVerticalTable()
  3585. */
  3586. private function _getOperationLinksForVerticleTable($operation)
  3587. {
  3588. $link_html = '<tr>' . "\n";
  3589. $vertical_display = $this->__get('vertical_display');
  3590. if (! is_array($vertical_display['row_delete'])) {
  3591. if (($operation == 'edit') || ($operation == 'copy')) {
  3592. $link_html .= $vertical_display['textbtn'];
  3593. } elseif ($operation == 'delete') {
  3594. if (! is_array($vertical_display['edit'])) {
  3595. $link_html .= $vertical_display['textbtn'];
  3596. }
  3597. }
  3598. }
  3599. foreach ($vertical_display[$operation] as $val) {
  3600. $link_html .= $val;
  3601. } // end while
  3602. $link_html .= '</tr>' . "\n";
  3603. return $link_html;
  3604. } // end of the '_getOperationLinksForVerticleTable' function
  3605. /**
  3606. * Get checkboxes for multiple row data operations
  3607. *
  3608. * @param string $dir _left / _right
  3609. * @param array $is_display display mode
  3610. *
  3611. * @return String $checkBoxes_html html content
  3612. *
  3613. * @access private
  3614. *
  3615. * @see _getVerticalTable()
  3616. */
  3617. private function _getCheckBoxesForMultipleRowOperations($dir, $is_display)
  3618. {
  3619. $checkBoxes_html = '';
  3620. $cell_displayed = 0;
  3621. $vertical_display = $this->__get('vertical_display');
  3622. foreach ($vertical_display['row_delete'] as $val) {
  3623. if (($cell_displayed != 0)
  3624. && ($_SESSION['tmpval']['repeat_cells'] != 0)
  3625. && !($cell_displayed % $_SESSION['tmpval']['repeat_cells'])
  3626. ) {
  3627. $checkBoxes_html .= '<th'
  3628. . (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  3629. && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
  3630. ? ' rowspan="4"'
  3631. : ''
  3632. . '></th>' . "\n";
  3633. }
  3634. $checkBoxes_html .= str_replace('[%_PMA_CHECKBOX_DIR_%]', $dir, $val);
  3635. $cell_displayed++;
  3636. } // end while
  3637. return $checkBoxes_html;
  3638. } // end of the '_getCheckBoxesForMultipleRowOperations' function
  3639. /**
  3640. * Checks the posted options for viewing query resutls
  3641. * and sets appropriate values in the session.
  3642. *
  3643. * @todo make maximum remembered queries configurable
  3644. * @todo move/split into SQL class!?
  3645. * @todo currently this is called twice unnecessary
  3646. * @todo ignore LIMIT and ORDER in query!?
  3647. *
  3648. * @return void
  3649. *
  3650. * @access public
  3651. *
  3652. * @see sql.php file
  3653. */
  3654. public function setConfigParamsForDisplayTable()
  3655. {
  3656. $sql_md5 = md5($this->__get('sql_query'));
  3657. $query = array();
  3658. if (isset($_SESSION['tmpval']['query'][$sql_md5])) {
  3659. $query = $_SESSION['tmpval']['query'][$sql_md5];
  3660. }
  3661. $query['sql'] = $this->__get('sql_query');
  3662. $valid_disp_dir = PMA_isValid(
  3663. $_REQUEST['disp_direction'],
  3664. array(self::DISP_DIR_HORIZONTAL, self::DISP_DIR_VERTICAL,
  3665. self::DISP_DIR_HORIZONTAL_FLIPPED
  3666. )
  3667. );
  3668. if ($valid_disp_dir) {
  3669. $query['disp_direction'] = $_REQUEST['disp_direction'];
  3670. unset($_REQUEST['disp_direction']);
  3671. } elseif (empty($query['disp_direction'])) {
  3672. $query['disp_direction'] = $GLOBALS['cfg']['DefaultDisplay'];
  3673. }
  3674. if (empty($query['repeat_cells'])) {
  3675. $query['repeat_cells'] = $GLOBALS['cfg']['RepeatCells'];
  3676. }
  3677. // as this is a form value, the type is always string so we cannot
  3678. // use PMA_isValid($_REQUEST['session_max_rows'], 'integer')
  3679. if (PMA_isValid($_REQUEST['session_max_rows'], 'numeric')) {
  3680. $query['max_rows'] = (int)$_REQUEST['session_max_rows'];
  3681. unset($_REQUEST['session_max_rows']);
  3682. } elseif ($_REQUEST['session_max_rows'] == self::ALL_ROWS) {
  3683. $query['max_rows'] = self::ALL_ROWS;
  3684. unset($_REQUEST['session_max_rows']);
  3685. } elseif (empty($query['max_rows'])) {
  3686. $query['max_rows'] = $GLOBALS['cfg']['MaxRows'];
  3687. }
  3688. if (PMA_isValid($_REQUEST['pos'], 'numeric')) {
  3689. $query['pos'] = $_REQUEST['pos'];
  3690. unset($_REQUEST['pos']);
  3691. } elseif (empty($query['pos'])) {
  3692. $query['pos'] = 0;
  3693. }
  3694. if (PMA_isValid(
  3695. $_REQUEST['pftext'],
  3696. array(
  3697. self::DISPLAY_PARTIAL_TEXT, self::DISPLAY_FULL_TEXT
  3698. )
  3699. )
  3700. ) {
  3701. $query['pftext'] = $_REQUEST['pftext'];
  3702. unset($_REQUEST['pftext']);
  3703. } elseif (empty($query['pftext'])) {
  3704. $query['pftext'] = self::DISPLAY_PARTIAL_TEXT;
  3705. }
  3706. if (PMA_isValid(
  3707. $_REQUEST['relational_display'],
  3708. array(
  3709. self::RELATIONAL_KEY, self::RELATIONAL_DISPLAY_COLUMN
  3710. )
  3711. )
  3712. ) {
  3713. $query['relational_display'] = $_REQUEST['relational_display'];
  3714. unset($_REQUEST['relational_display']);
  3715. } elseif (empty($query['relational_display'])) {
  3716. $query['relational_display'] = self::RELATIONAL_KEY;
  3717. }
  3718. if (PMA_isValid(
  3719. $_REQUEST['geoOption'],
  3720. array(
  3721. self::GEOMETRY_DISP_WKT, self::GEOMETRY_DISP_WKB,
  3722. self::GEOMETRY_DISP_GEOM
  3723. )
  3724. )
  3725. ) {
  3726. $query['geoOption'] = $_REQUEST['geoOption'];
  3727. unset($_REQUEST['geoOption']);
  3728. } elseif (empty($query['geoOption'])) {
  3729. $query['geoOption'] = self::GEOMETRY_DISP_GEOM;
  3730. }
  3731. if (isset($_REQUEST['display_binary'])) {
  3732. $query['display_binary'] = true;
  3733. unset($_REQUEST['display_binary']);
  3734. } elseif (isset($_REQUEST['display_options_form'])) {
  3735. // we know that the checkbox was unchecked
  3736. unset($query['display_binary']);
  3737. } elseif (isset($_REQUEST['full_text_button'])) {
  3738. // do nothing to keep the value that is there in the session
  3739. } else {
  3740. // selected by default because some operations like OPTIMIZE TABLE
  3741. // and all queries involving functions return "binary" contents,
  3742. // according to low-level field flags
  3743. $query['display_binary'] = true;
  3744. }
  3745. if (isset($_REQUEST['display_binary_as_hex'])) {
  3746. $query['display_binary_as_hex'] = true;
  3747. unset($_REQUEST['display_binary_as_hex']);
  3748. } elseif (isset($_REQUEST['display_options_form'])) {
  3749. // we know that the checkbox was unchecked
  3750. unset($query['display_binary_as_hex']);
  3751. } elseif (isset($_REQUEST['full_text_button'])) {
  3752. // do nothing to keep the value that is there in the session
  3753. } else {
  3754. // display_binary_as_hex config option
  3755. if (isset($GLOBALS['cfg']['DisplayBinaryAsHex'])
  3756. && ($GLOBALS['cfg']['DisplayBinaryAsHex'] === true)
  3757. ) {
  3758. $query['display_binary_as_hex'] = true;
  3759. }
  3760. }
  3761. if (isset($_REQUEST['display_blob'])) {
  3762. $query['display_blob'] = true;
  3763. unset($_REQUEST['display_blob']);
  3764. } elseif (isset($_REQUEST['display_options_form'])) {
  3765. // we know that the checkbox was unchecked
  3766. unset($query['display_blob']);
  3767. }
  3768. if (isset($_REQUEST['hide_transformation'])) {
  3769. $query['hide_transformation'] = true;
  3770. unset($_REQUEST['hide_transformation']);
  3771. } elseif (isset($_REQUEST['display_options_form'])) {
  3772. // we know that the checkbox was unchecked
  3773. unset($query['hide_transformation']);
  3774. }
  3775. // move current query to the last position, to be removed last
  3776. // so only least executed query will be removed if maximum remembered
  3777. // queries limit is reached
  3778. unset($_SESSION['tmpval']['query'][$sql_md5]);
  3779. $_SESSION['tmpval']['query'][$sql_md5] = $query;
  3780. // do not exceed a maximum number of queries to remember
  3781. if (count($_SESSION['tmpval']['query']) > 10) {
  3782. array_shift($_SESSION['tmpval']['query']);
  3783. //echo 'deleting one element ...';
  3784. }
  3785. // populate query configuration
  3786. $_SESSION['tmpval']['pftext']
  3787. = $query['pftext'];
  3788. $_SESSION['tmpval']['relational_display']
  3789. = $query['relational_display'];
  3790. $_SESSION['tmpval']['geoOption']
  3791. = $query['geoOption'];
  3792. $_SESSION['tmpval']['display_binary'] = isset(
  3793. $query['display_binary']
  3794. );
  3795. $_SESSION['tmpval']['display_binary_as_hex'] = isset(
  3796. $query['display_binary_as_hex']
  3797. );
  3798. $_SESSION['tmpval']['display_blob'] = isset(
  3799. $query['display_blob']
  3800. );
  3801. $_SESSION['tmpval']['hide_transformation'] = isset(
  3802. $query['hide_transformation']
  3803. );
  3804. $_SESSION['tmpval']['pos']
  3805. = $query['pos'];
  3806. $_SESSION['tmpval']['max_rows']
  3807. = $query['max_rows'];
  3808. $_SESSION['tmpval']['repeat_cells']
  3809. = $query['repeat_cells'];
  3810. $_SESSION['tmpval']['disp_direction']
  3811. = $query['disp_direction'];
  3812. }
  3813. /**
  3814. * Prepare a table of results returned by a SQL query.
  3815. * This function is called by the "sql.php" script.
  3816. *
  3817. * @param integer &$dt_result the link id associated to the query
  3818. * which results have to be displayed
  3819. * @param array &$the_disp_mode the display mode
  3820. * @param array $analyzed_sql the analyzed query
  3821. * @param boolean $is_limited_display With limited operations or not
  3822. *
  3823. * @return string $table_html Generated HTML content for resulted table
  3824. *
  3825. * @access public
  3826. *
  3827. * @see sql.php file
  3828. */
  3829. public function getTable(
  3830. &$dt_result, &$the_disp_mode, $analyzed_sql,
  3831. $is_limited_display = false
  3832. ) {
  3833. $table_html = '';
  3834. // Following variable are needed for use in isset/empty or
  3835. // use with array indexes/safe use in foreach
  3836. $fields_meta = $this->__get('fields_meta');
  3837. $showtable = $this->__get('showtable');
  3838. $printview = $this->__get('printview');
  3839. // why was this called here? (already called from sql.php)
  3840. //$this->setConfigParamsForDisplayTable();
  3841. /**
  3842. * @todo move this to a central place
  3843. * @todo for other future table types
  3844. */
  3845. $is_innodb = (isset($showtable['Type'])
  3846. && $showtable['Type'] == self::TABLE_TYPE_INNO_DB);
  3847. if ($is_innodb
  3848. && ! isset($analyzed_sql[0]['queryflags']['union'])
  3849. && ! isset($analyzed_sql[0]['table_ref'][1]['table_name'])
  3850. && (empty($analyzed_sql[0]['where_clause'])
  3851. || ($analyzed_sql[0]['where_clause'] == '1 '))
  3852. ) {
  3853. // "j u s t b r o w s i n g"
  3854. $pre_count = '~';
  3855. $after_count = PMA_Util::showHint(
  3856. PMA_sanitize(
  3857. __('May be approximate. See [doc@faq3-11]FAQ 3.11[/doc].')
  3858. )
  3859. );
  3860. } else {
  3861. $pre_count = '';
  3862. $after_count = '';
  3863. }
  3864. // 1. ----- Prepares the work -----
  3865. // 1.1 Gets the informations about which functionalities should be
  3866. // displayed
  3867. $total = '';
  3868. $is_display = $this->_setDisplayMode($the_disp_mode, $total);
  3869. // 1.2 Defines offsets for the next and previous pages
  3870. if ($is_display['nav_bar'] == '1') {
  3871. list($pos_next, $pos_prev) = $this->_getOffsets();
  3872. } // end if
  3873. if (!isset($analyzed_sql[0]['order_by_clause'])) {
  3874. $analyzed_sql[0]['order_by_clause'] = "";
  3875. }
  3876. // 1.3 Find the sort expression
  3877. // we need $sort_expression and $sort_expression_nodirection
  3878. // even if there are many table references
  3879. list(
  3880. $sort_expression, $sort_expression_nodirection,
  3881. $sort_direction
  3882. ) = $this->_getSortParams($analyzed_sql[0]['order_by_clause']);
  3883. $number_of_columns = count($sort_expression_nodirection);
  3884. // 1.4 Prepares display of first and last value of the sorted column
  3885. $sorted_column_message = '';
  3886. for ( $i = 0; $i < $number_of_columns; $i++ ) {
  3887. $sorted_column_message .= $this->_getSortedColumnMessage(
  3888. $dt_result, $sort_expression_nodirection[$i]
  3889. );
  3890. }
  3891. // 2. ----- Prepare to display the top of the page -----
  3892. // 2.1 Prepares a messages with position informations
  3893. if (($is_display['nav_bar'] == '1') && isset($pos_next)) {
  3894. $message = $this->_setMessageInformation(
  3895. $sorted_column_message, $analyzed_sql[0]['limit_clause'],
  3896. $total, $pos_next, $pre_count, $after_count
  3897. );
  3898. $table_html .= PMA_Util::getMessage(
  3899. $message, $this->__get('sql_query'), 'success'
  3900. );
  3901. } elseif (! isset($printview) || ($printview != '1')) {
  3902. $table_html .= PMA_Util::getMessage(
  3903. __('Your SQL query has been executed successfully.'),
  3904. $this->__get('sql_query'), 'success'
  3905. );
  3906. }
  3907. // 2.3 Prepare the navigation bars
  3908. if (! strlen($this->__get('table'))) {
  3909. if (isset($analyzed_sql[0]['query_type'])
  3910. && ($analyzed_sql[0]['query_type'] == self::QUERY_TYPE_SELECT)
  3911. ) {
  3912. // table does not always contain a real table name,
  3913. // for example in MySQL 5.0.x, the query SHOW STATUS
  3914. // returns STATUS as a table name
  3915. $this->__set('table', $fields_meta[0]->table);
  3916. } else {
  3917. $this->__set('table', '');
  3918. }
  3919. }
  3920. if (($is_display['nav_bar'] == '1')
  3921. && empty($analyzed_sql[0]['limit_clause'])
  3922. ) {
  3923. $table_html .= $this->_getPlacedTableNavigations(
  3924. $pos_next, $pos_prev, self::PLACE_TOP_DIRECTION_DROPDOWN,
  3925. "\n", $is_innodb
  3926. );
  3927. } elseif (! isset($printview) || ($printview != '1')) {
  3928. $table_html .= "\n" . '<br /><br />' . "\n";
  3929. }
  3930. // 2b ----- Get field references from Database -----
  3931. // (see the 'relation' configuration variable)
  3932. // initialize map
  3933. $map = array();
  3934. // find tables
  3935. $target=array();
  3936. if (isset($analyzed_sql[0]['table_ref'])
  3937. && is_array($analyzed_sql[0]['table_ref'])
  3938. ) {
  3939. foreach ($analyzed_sql[0]['table_ref']
  3940. as $table_ref_position => $table_ref) {
  3941. $target[] = $analyzed_sql[0]['table_ref']
  3942. [$table_ref_position]['table_true_name'];
  3943. }
  3944. }
  3945. if (strlen($this->__get('table'))) {
  3946. // This method set the values for $map array
  3947. $this->_setParamForLinkForeignKeyRelatedTables($map);
  3948. } // end if
  3949. // end 2b
  3950. // 3. ----- Prepare the results table -----
  3951. $table_html .= $this->_getTableHeaders(
  3952. $is_display, $analyzed_sql, $sort_expression,
  3953. $sort_expression_nodirection, $sort_direction, $is_limited_display
  3954. )
  3955. . '<tbody>' . "\n";
  3956. $table_html .= $this->_getTableBody(
  3957. $dt_result, $is_display, $map, $analyzed_sql, $is_limited_display
  3958. );
  3959. // vertical output case
  3960. if ($_SESSION['tmpval']['disp_direction'] == self::DISP_DIR_VERTICAL) {
  3961. $table_html .= $this->_getVerticalTable($analyzed_sql, $is_display);
  3962. } // end if
  3963. $this->__set('vertical_display', null);
  3964. $table_html .= '</tbody>' . "\n"
  3965. . '</table>';
  3966. // 4. ----- Prepares the link for multi-fields edit and delete
  3967. if ($is_display['del_lnk'] == self::DELETE_ROW
  3968. && $is_display['del_lnk'] != self::KILL_PROCESS
  3969. ) {
  3970. $table_html .= $this->_getMultiRowOperationLinks(
  3971. $dt_result, $analyzed_sql, $is_display['del_lnk']
  3972. );
  3973. }
  3974. // 5. ----- Get the navigation bar at the bottom if required -----
  3975. if (($is_display['nav_bar'] == '1')
  3976. && empty($analyzed_sql[0]['limit_clause'])
  3977. ) {
  3978. $table_html .= $this->_getPlacedTableNavigations(
  3979. $pos_next, $pos_prev, self::PLACE_BOTTOM_DIRECTION_DROPDOWN,
  3980. '<br />' . "\n", $is_innodb
  3981. );
  3982. } elseif (! isset($printview) || ($printview != '1')) {
  3983. $table_html .= "\n" . '<br /><br />' . "\n";
  3984. }
  3985. // 6. ----- Prepare "Query results operations"
  3986. if ((! isset($printview) || ($printview != '1')) && ! $is_limited_display) {
  3987. $table_html .= $this->_getResultsOperations(
  3988. $the_disp_mode, $analyzed_sql
  3989. );
  3990. }
  3991. return $table_html;
  3992. } // end of the 'getTable()' function
  3993. /**
  3994. * Get offsets for next page and previous page
  3995. *
  3996. * @return array array with two elements - $pos_next, $pos_prev
  3997. *
  3998. * @access private
  3999. *
  4000. * @see getTable()
  4001. */
  4002. private function _getOffsets()
  4003. {
  4004. if ($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS) {
  4005. $pos_next = 0;
  4006. $pos_prev = 0;
  4007. } else {
  4008. $pos_next = $_SESSION['tmpval']['pos']
  4009. + $_SESSION['tmpval']['max_rows'];
  4010. $pos_prev = $_SESSION['tmpval']['pos']
  4011. - $_SESSION['tmpval']['max_rows'];
  4012. if ($pos_prev < 0) {
  4013. $pos_prev = 0;
  4014. }
  4015. }
  4016. return array($pos_next, $pos_prev);
  4017. } // end of the '_getOffsets()' function
  4018. /**
  4019. * Get sort parameters
  4020. *
  4021. * @param string $order_by_clause the order by clause of the sql query
  4022. *
  4023. * @return array 3 element array: $sort_expression,
  4024. * $sort_expression_nodirection, $sort_direction
  4025. *
  4026. * @access private
  4027. *
  4028. * @see getTable()
  4029. */
  4030. private function _getSortParams($order_by_clause)
  4031. {
  4032. $sort_expression = array();
  4033. $sort_expression_nodirection = array();
  4034. $sort_direction = array();
  4035. if (! empty($order_by_clause)) {
  4036. // Each order by clause is assumed to be delimited by a comma
  4037. // A typical order by clause would be order by column1 asc, column2 desc
  4038. // The following line counts the number of columns in order by clause
  4039. $matches = explode(',', $order_by_clause);
  4040. // Iterate over each column in order by clause
  4041. foreach ($matches as $index=>$order_by_clause2) {
  4042. $sort_expression[$index] = trim(
  4043. str_replace(' ', ' ', $order_by_clause2)
  4044. );
  4045. /**
  4046. * Get rid of ASC|DESC
  4047. */
  4048. preg_match(
  4049. '@(.*)([[:space:]]*(ASC|DESC))@si',
  4050. $sort_expression[$index], $matches
  4051. );
  4052. $sort_expression_nodirection[$index] = isset($matches[1])
  4053. ? trim($matches[1])
  4054. : $sort_expression[$index];
  4055. $sort_direction[$index]
  4056. = isset($matches[2]) ? trim($matches[2]) : '';
  4057. }
  4058. } else {
  4059. $sort_expression[0] = $sort_expression_nodirection[0]
  4060. = $sort_direction[0] = '';
  4061. }
  4062. return array($sort_expression, $sort_expression_nodirection,
  4063. $sort_direction
  4064. );
  4065. } // end of the '_getSortParams()' function
  4066. /**
  4067. * Prepare sorted column message
  4068. *
  4069. * @param integer &$dt_result the link id associated to the
  4070. * query which results have to
  4071. * be displayed
  4072. * @param string $sort_expression_nodirection sort expression without direction
  4073. *
  4074. * @return string html content
  4075. * null if not found sorted column
  4076. *
  4077. * @access private
  4078. *
  4079. * @see getTable()
  4080. */
  4081. private function _getSortedColumnMessage(
  4082. &$dt_result, $sort_expression_nodirection
  4083. ) {
  4084. $fields_meta = $this->__get('fields_meta'); // To use array indexes
  4085. if (! empty($sort_expression_nodirection)) {
  4086. if (strpos($sort_expression_nodirection, '.') === false) {
  4087. $sort_table = $this->__get('table');
  4088. $sort_column = $sort_expression_nodirection;
  4089. } else {
  4090. list($sort_table, $sort_column)
  4091. = explode('.', $sort_expression_nodirection);
  4092. }
  4093. $sort_table = PMA_Util::unQuote($sort_table);
  4094. $sort_column = PMA_Util::unQuote($sort_column);
  4095. // find the sorted column index in row result
  4096. // (this might be a multi-table query)
  4097. $sorted_column_index = false;
  4098. foreach ($fields_meta as $key => $meta) {
  4099. if (($meta->table == $sort_table) && ($meta->name == $sort_column)) {
  4100. $sorted_column_index = $key;
  4101. break;
  4102. }
  4103. }
  4104. if ($sorted_column_index !== false) {
  4105. // fetch first row of the result set
  4106. $row = $GLOBALS['dbi']->fetchRow($dt_result);
  4107. // initializing default arguments
  4108. $default_function = '_mimeDefaultFunction';
  4109. $transformation_plugin = $default_function;
  4110. $transform_options = array();
  4111. // check for non printable sorted row data
  4112. $meta = $fields_meta[$sorted_column_index];
  4113. if (stristr($meta->type, self::BLOB_FIELD)
  4114. || ($meta->type == self::GEOMETRY_FIELD)
  4115. ) {
  4116. $column_for_first_row = $this->_handleNonPrintableContents(
  4117. $meta->type, $row[$sorted_column_index],
  4118. $transformation_plugin, $transform_options,
  4119. $default_function, $meta
  4120. );
  4121. } else {
  4122. $column_for_first_row = $row[$sorted_column_index];
  4123. }
  4124. $column_for_first_row = strtoupper(
  4125. substr($column_for_first_row, 0, $GLOBALS['cfg']['LimitChars'])
  4126. );
  4127. // fetch last row of the result set
  4128. $GLOBALS['dbi']->dataSeek($dt_result, $this->__get('num_rows') - 1);
  4129. $row = $GLOBALS['dbi']->fetchRow($dt_result);
  4130. // check for non printable sorted row data
  4131. $meta = $fields_meta[$sorted_column_index];
  4132. if (stristr($meta->type, self::BLOB_FIELD)
  4133. || ($meta->type == self::GEOMETRY_FIELD)
  4134. ) {
  4135. $column_for_last_row = $this->_handleNonPrintableContents(
  4136. $meta->type, $row[$sorted_column_index],
  4137. $transformation_plugin, $transform_options,
  4138. $default_function, $meta
  4139. );
  4140. } else {
  4141. $column_for_last_row = $row[$sorted_column_index];
  4142. }
  4143. $column_for_last_row = strtoupper(
  4144. substr($column_for_last_row, 0, $GLOBALS['cfg']['LimitChars'])
  4145. );
  4146. // reset to first row for the loop in _getTableBody()
  4147. $GLOBALS['dbi']->dataSeek($dt_result, 0);
  4148. // we could also use here $sort_expression_nodirection
  4149. return ' [' . htmlspecialchars($sort_column)
  4150. . ': <strong>' . htmlspecialchars($column_for_first_row) . ' - '
  4151. . htmlspecialchars($column_for_last_row) . '</strong>]';
  4152. }
  4153. }
  4154. return null;
  4155. } // end of the '_getSortedColumnMessage()' function
  4156. /**
  4157. * Set the content that needs to be shown in message
  4158. *
  4159. * @param string $sorted_column_message the message for sorted column
  4160. * @param string $limit_clause the limit clause of analyzed query
  4161. * @param integer $total the total number of rows returned by
  4162. * the SQL query without any
  4163. * programmatically appended LIMIT clause
  4164. * @param integer $pos_next the offset for next page
  4165. * @param string $pre_count the string renders before row count
  4166. * @param string $after_count the string renders after row count
  4167. *
  4168. * @return PMA_Message $message an object of PMA_Message
  4169. *
  4170. * @access private
  4171. *
  4172. * @see getTable()
  4173. */
  4174. private function _setMessageInformation(
  4175. $sorted_column_message, $limit_clause, $total,
  4176. $pos_next, $pre_count, $after_count
  4177. ) {
  4178. $unlim_num_rows = $this->__get('unlim_num_rows'); // To use in isset()
  4179. if (! empty($limit_clause)) {
  4180. $limit_data
  4181. = PMA_Util::analyzeLimitClause($limit_clause);
  4182. $first_shown_rec = $limit_data['start'];
  4183. if ($limit_data['length'] < $total) {
  4184. $last_shown_rec = $limit_data['start'] + $limit_data['length'] - 1;
  4185. } else {
  4186. $last_shown_rec = $limit_data['start'] + $total - 1;
  4187. }
  4188. } elseif (($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS)
  4189. || ($pos_next > $total)
  4190. ) {
  4191. $first_shown_rec = $_SESSION['tmpval']['pos'];
  4192. $last_shown_rec = $total - 1;
  4193. } else {
  4194. $first_shown_rec = $_SESSION['tmpval']['pos'];
  4195. $last_shown_rec = $pos_next - 1;
  4196. }
  4197. if (PMA_Table::isView($this->__get('db'), $this->__get('table'))
  4198. && ($total == $GLOBALS['cfg']['MaxExactCountViews'])
  4199. ) {
  4200. $message = PMA_Message::notice(
  4201. __(
  4202. 'This view has at least this number of rows. '
  4203. . 'Please refer to %sdocumentation%s.'
  4204. )
  4205. );
  4206. $message->addParam('[doc@cfg_MaxExactCount]');
  4207. $message->addParam('[/doc]');
  4208. $message_view_warning = PMA_Util::showHint($message);
  4209. } else {
  4210. $message_view_warning = false;
  4211. }
  4212. $message = PMA_Message::success(__('Showing rows %1s - %2s'));
  4213. $message->addParam($first_shown_rec);
  4214. if ($message_view_warning) {
  4215. $message->addParam('... ' . $message_view_warning, false);
  4216. } else {
  4217. $message->addParam($last_shown_rec);
  4218. }
  4219. $message->addMessage('(');
  4220. if (!$message_view_warning) {
  4221. if (isset($unlim_num_rows) && ($unlim_num_rows != $total)) {
  4222. $message_total = PMA_Message::notice(
  4223. $pre_count . __('%1$d total, %2$d in query')
  4224. );
  4225. $message_total->addParam($total);
  4226. $message_total->addParam($unlim_num_rows);
  4227. } else {
  4228. $message_total = PMA_Message::notice($pre_count . __('%d total'));
  4229. $message_total->addParam($total);
  4230. }
  4231. if (!empty($after_count)) {
  4232. $message_total->addMessage($after_count);
  4233. }
  4234. $message->addMessage($message_total, '');
  4235. $message->addMessage(', ', '');
  4236. }
  4237. $message_qt = PMA_Message::notice(__('Query took %01.4f seconds.') . ')');
  4238. $message_qt->addParam($this->__get('querytime'));
  4239. $message->addMessage($message_qt, '');
  4240. if (! is_null($sorted_column_message)) {
  4241. $message->addMessage($sorted_column_message, '');
  4242. }
  4243. return $message;
  4244. } // end of the '_setMessageInformation()' function
  4245. /**
  4246. * Set the value of $map array for linking foreign key related tables
  4247. *
  4248. * @param array &$map the list of relations
  4249. *
  4250. * @return void
  4251. *
  4252. * @access private
  4253. *
  4254. * @see getTable()
  4255. */
  4256. private function _setParamForLinkForeignKeyRelatedTables(&$map)
  4257. {
  4258. // To be able to later display a link to the related table,
  4259. // we verify both types of relations: either those that are
  4260. // native foreign keys or those defined in the phpMyAdmin
  4261. // configuration storage. If no PMA storage, we won't be able
  4262. // to use the "column to display" notion (for example show
  4263. // the name related to a numeric id).
  4264. $exist_rel = PMA_getForeigners(
  4265. $this->__get('db'), $this->__get('table'), '', self::POSITION_BOTH
  4266. );
  4267. if ($exist_rel) {
  4268. foreach ($exist_rel as $master_field => $rel) {
  4269. $display_field = PMA_getDisplayField(
  4270. $rel['foreign_db'], $rel['foreign_table']
  4271. );
  4272. $map[$master_field] = array(
  4273. $rel['foreign_table'],
  4274. $rel['foreign_field'],
  4275. $display_field,
  4276. $rel['foreign_db']
  4277. );
  4278. } // end while
  4279. } // end if
  4280. } // end of the '_setParamForLinkForeignKeyRelatedTables()' function
  4281. /**
  4282. * Prepare multi field edit/delete links
  4283. *
  4284. * @param integer &$dt_result the link id associated to the query
  4285. * which results have to be displayed
  4286. * @param array $analyzed_sql the analyzed query
  4287. * @param string $del_link the display element - 'del_link'
  4288. *
  4289. * @return string $links_html html content
  4290. *
  4291. * @access private
  4292. *
  4293. * @see getTable()
  4294. */
  4295. private function _getMultiRowOperationLinks(
  4296. &$dt_result, $analyzed_sql, $del_link
  4297. ) {
  4298. $links_html = '';
  4299. $url_query = $this->__get('url_query');
  4300. $delete_text = ($del_link == self::DELETE_ROW) ? __('Delete') : __('Kill');
  4301. if ($_SESSION['tmpval']['disp_direction'] != self::DISP_DIR_VERTICAL) {
  4302. $links_html .= '<img class="selectallarrow" width="38" height="22"'
  4303. . ' src="' . $this->__get('pma_theme_image') . 'arrow_'
  4304. . $this->__get('text_dir') . '.png' . '"'
  4305. . ' alt="' . __('With selected:') . '" />';
  4306. }
  4307. $links_html .= '<input type="checkbox" id="resultsForm_checkall" '
  4308. . 'class="checkall_box" title="' . __('Check All') . '" /> '
  4309. . '<label for="resultsForm_checkall">' . __('Check All') . '</label> '
  4310. . '<i style="margin-left: 2em">' . __('With selected:') . '</i>' . "\n";
  4311. $links_html .= PMA_Util::getButtonOrImage(
  4312. 'submit_mult', 'mult_submit', 'submit_mult_change',
  4313. __('Change'), 'b_edit.png', 'edit'
  4314. );
  4315. $links_html .= PMA_Util::getButtonOrImage(
  4316. 'submit_mult', 'mult_submit', 'submit_mult_delete',
  4317. $delete_text, 'b_drop.png', 'delete'
  4318. );
  4319. if (isset($analyzed_sql[0])
  4320. && $analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT
  4321. ) {
  4322. $links_html .= PMA_Util::getButtonOrImage(
  4323. 'submit_mult', 'mult_submit', 'submit_mult_export',
  4324. __('Export'), 'b_tblexport.png', 'export'
  4325. );
  4326. }
  4327. $links_html .= "\n";
  4328. $links_html .= '<input type="hidden" name="sql_query"'
  4329. . ' value="' . htmlspecialchars($this->__get('sql_query')) . '" />'
  4330. . "\n";
  4331. if (! empty($url_query)) {
  4332. $links_html .= '<input type="hidden" name="url_query"'
  4333. . ' value="' . $url_query . '" />' . "\n";
  4334. }
  4335. // fetch last row of the result set
  4336. $GLOBALS['dbi']->dataSeek($dt_result, $this->__get('num_rows') - 1);
  4337. $row = $GLOBALS['dbi']->fetchRow($dt_result);
  4338. // $clause_is_unique is needed by getTable() to generate the proper param
  4339. // in the multi-edit and multi-delete form
  4340. list($where_clause, $clause_is_unique, $condition_array)
  4341. = PMA_Util::getUniqueCondition(
  4342. $dt_result,
  4343. $this->__get('fields_cnt'),
  4344. $this->__get('fields_meta'),
  4345. $row
  4346. );
  4347. unset($where_clause, $condition_array);
  4348. // reset to first row for the loop in _getTableBody()
  4349. $GLOBALS['dbi']->dataSeek($dt_result, 0);
  4350. $links_html .= '<input type="hidden" name="clause_is_unique"'
  4351. . ' value="' . $clause_is_unique . '" />' . "\n";
  4352. $links_html .= '</form>' . "\n";
  4353. return $links_html;
  4354. } // end of the '_getMultiRowOperationLinks()' function
  4355. /**
  4356. * Prepare table navigation bar at the top or bottom
  4357. *
  4358. * @param integer $pos_next the offset for the "next" page
  4359. * @param integer $pos_prev the offset for the "previous" page
  4360. * @param string $place the place to show navigation
  4361. * @param string $empty_line empty line depend on the $place
  4362. * @param boolean $is_innodb whether its InnoDB or not
  4363. *
  4364. * @return string html content of navigation bar
  4365. *
  4366. * @access private
  4367. *
  4368. * @see _getTable()
  4369. */
  4370. private function _getPlacedTableNavigations(
  4371. $pos_next, $pos_prev, $place, $empty_line, $is_innodb
  4372. ) {
  4373. $navigation_html = '';
  4374. if ($place == self::PLACE_BOTTOM_DIRECTION_DROPDOWN) {
  4375. $navigation_html .= '<br />' . "\n";
  4376. }
  4377. $navigation_html .= $this->_getTableNavigation(
  4378. $pos_next, $pos_prev, 'top_direction_dropdown', $is_innodb
  4379. );
  4380. if ($place == self::PLACE_TOP_DIRECTION_DROPDOWN) {
  4381. $navigation_html .= "\n";
  4382. }
  4383. return $navigation_html;
  4384. } // end of the '_getPlacedTableNavigations()' function
  4385. /**
  4386. * Generates HTML to display the Create view in span tag
  4387. *
  4388. * @param array $analyzed_sql the analyzed Query
  4389. * @param string $url_query String with URL Parameters
  4390. *
  4391. * @return string
  4392. *
  4393. * @access private
  4394. *
  4395. * @see _getResultsOperations()
  4396. */
  4397. private function _getLinkForCreateView($analyzed_sql, $url_query)
  4398. {
  4399. $results_operations_html = '';
  4400. if (!PMA_DRIZZLE && !isset($analyzed_sql[0]['queryflags']['procedure'])) {
  4401. $ajax_class = ' ajax';
  4402. $results_operations_html .= '<span>'
  4403. . PMA_Util::linkOrButton(
  4404. 'view_create.php' . $url_query,
  4405. PMA_Util::getIcon(
  4406. 'b_views.png', __('Create view'), true
  4407. ),
  4408. array('class' => 'create_view' . $ajax_class), true, true, ''
  4409. )
  4410. . '</span>' . "\n";
  4411. }
  4412. return $results_operations_html;
  4413. }
  4414. /**
  4415. * Calls the _getResultsOperations with $only_view as true
  4416. *
  4417. * @param array $analyzed_sql the analyzed Query
  4418. *
  4419. * @return string
  4420. *
  4421. * @access public
  4422. *
  4423. */
  4424. public function getCreateViewQueryResultOp($analyzed_sql)
  4425. {
  4426. $results_operations_html = '';
  4427. $fake_display_mode = array();
  4428. //calling to _getResultOperations with a fake display mode
  4429. //and setting only_view parameter to be true to generate just view
  4430. $results_operations_html .= $this->_getResultsOperations(
  4431. $fake_display_mode,
  4432. $analyzed_sql,
  4433. true
  4434. );
  4435. return $results_operations_html;
  4436. }
  4437. /**
  4438. * Get operations that are available on results.
  4439. *
  4440. * @param array $the_disp_mode the display mode
  4441. * @param array $analyzed_sql the analyzed query
  4442. * @param boolean $only_view Whether to show only view
  4443. *
  4444. * @return string $results_operations_html html content
  4445. *
  4446. * @access private
  4447. *
  4448. * @see getTable()
  4449. */
  4450. private function _getResultsOperations(
  4451. $the_disp_mode, $analyzed_sql, $only_view = false
  4452. ) {
  4453. global $printview;
  4454. $results_operations_html = '';
  4455. $fields_meta = $this->__get('fields_meta'); // To safe use in foreach
  4456. $header_shown = false;
  4457. $header = '<fieldset><legend>' . __('Query results operations')
  4458. . '</legend>';
  4459. $_url_params = array(
  4460. 'db' => $this->__get('db'),
  4461. 'table' => $this->__get('table'),
  4462. 'printview' => '1',
  4463. 'sql_query' => $this->__get('sql_query'),
  4464. );
  4465. $url_query = PMA_URL_getCommon($_url_params);
  4466. if (!$header_shown) {
  4467. $results_operations_html .= $header;
  4468. $header_shown = true;
  4469. }
  4470. // if empty result set was produced we need to
  4471. // show only view and not other options
  4472. if ($only_view == true) {
  4473. $results_operations_html .= $this->_getLinkForCreateView(
  4474. $analyzed_sql, $url_query
  4475. );
  4476. if ($header_shown) {
  4477. $results_operations_html .= '</fieldset><br />';
  4478. }
  4479. return $results_operations_html;
  4480. }
  4481. if (($the_disp_mode[6] == '1') || ($the_disp_mode[9] == '1')) {
  4482. // Displays "printable view" link if required
  4483. if ($the_disp_mode[9] == '1') {
  4484. $results_operations_html
  4485. .= PMA_Util::linkOrButton(
  4486. 'sql.php' . $url_query,
  4487. PMA_Util::getIcon(
  4488. 'b_print.png', __('Print view'), true
  4489. ),
  4490. array('target' => 'print_view'),
  4491. true,
  4492. true,
  4493. 'print_view'
  4494. )
  4495. . "\n";
  4496. if ($_SESSION['tmpval']['pftext']) {
  4497. $_url_params['pftext'] = self::DISPLAY_FULL_TEXT;
  4498. $results_operations_html
  4499. .= PMA_Util::linkOrButton(
  4500. 'sql.php' . PMA_URL_getCommon($_url_params),
  4501. PMA_Util::getIcon(
  4502. 'b_print.png',
  4503. __('Print view (with full texts)'), true
  4504. ),
  4505. array('target' => 'print_view'),
  4506. true,
  4507. true,
  4508. 'print_view'
  4509. )
  4510. . "\n";
  4511. unset($_url_params['pftext']);
  4512. }
  4513. } // end displays "printable view"
  4514. }
  4515. // Export link
  4516. // (the url_query has extra parameters that won't be used to export)
  4517. // (the single_table parameter is used in display_export.inc.php
  4518. // to hide the SQL and the structure export dialogs)
  4519. // If the parser found a PROCEDURE clause
  4520. // (most probably PROCEDURE ANALYSE()) it makes no sense to
  4521. // display the Export link).
  4522. if (isset($analyzed_sql[0])
  4523. && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT)
  4524. && ! isset($printview)
  4525. && ! isset($analyzed_sql[0]['queryflags']['procedure'])
  4526. ) {
  4527. if (isset($analyzed_sql[0]['table_ref'][0]['table_true_name'])
  4528. && ! isset($analyzed_sql[0]['table_ref'][1]['table_true_name'])
  4529. ) {
  4530. $_url_params['single_table'] = 'true';
  4531. }
  4532. if (! $header_shown) {
  4533. $results_operations_html .= $header;
  4534. $header_shown = true;
  4535. }
  4536. $_url_params['unlim_num_rows'] = $this->__get('unlim_num_rows');
  4537. /**
  4538. * At this point we don't know the table name; this can happen
  4539. * for example with a query like
  4540. * SELECT bike_code FROM (SELECT bike_code FROM bikes) tmp
  4541. * As a workaround we set in the table parameter the name of the
  4542. * first table of this database, so that tbl_export.php and
  4543. * the script it calls do not fail
  4544. */
  4545. if (empty($_url_params['table']) && ! empty($_url_params['db'])) {
  4546. $_url_params['table'] = $GLOBALS['dbi']->fetchValue("SHOW TABLES");
  4547. /* No result (probably no database selected) */
  4548. if ($_url_params['table'] === false) {
  4549. unset($_url_params['table']);
  4550. }
  4551. }
  4552. $results_operations_html .= PMA_Util::linkOrButton(
  4553. 'tbl_export.php' . PMA_URL_getCommon($_url_params),
  4554. PMA_Util::getIcon(
  4555. 'b_tblexport.png', __('Export'), true
  4556. ),
  4557. '',
  4558. true,
  4559. true,
  4560. ''
  4561. )
  4562. . "\n";
  4563. // prepare chart
  4564. $results_operations_html .= PMA_Util::linkOrButton(
  4565. 'tbl_chart.php' . PMA_URL_getCommon($_url_params),
  4566. PMA_Util::getIcon(
  4567. 'b_chart.png', __('Display chart'), true
  4568. ),
  4569. '',
  4570. true,
  4571. true,
  4572. ''
  4573. )
  4574. . "\n";
  4575. // prepare GIS chart
  4576. $geometry_found = false;
  4577. // If atleast one geometry field is found
  4578. foreach ($fields_meta as $meta) {
  4579. if ($meta->type == self::GEOMETRY_FIELD) {
  4580. $geometry_found = true;
  4581. break;
  4582. }
  4583. }
  4584. if ($geometry_found) {
  4585. $results_operations_html
  4586. .= PMA_Util::linkOrButton(
  4587. 'tbl_gis_visualization.php'
  4588. . PMA_URL_getCommon($_url_params),
  4589. PMA_Util::getIcon(
  4590. 'b_globe.gif', __('Visualize GIS data'), true
  4591. ),
  4592. '',
  4593. true,
  4594. true,
  4595. ''
  4596. )
  4597. . "\n";
  4598. }
  4599. }
  4600. // CREATE VIEW
  4601. /**
  4602. *
  4603. * @todo detect privileges to create a view
  4604. * (but see 2006-01-19 note in display_create_table.lib.php,
  4605. * I think we cannot detect db-specific privileges reliably)
  4606. * Note: we don't display a Create view link if we found a PROCEDURE clause
  4607. */
  4608. if (!$header_shown) {
  4609. $results_operations_html .= $header;
  4610. $header_shown = true;
  4611. }
  4612. $results_operations_html .= $this->_getLinkForCreateView(
  4613. $analyzed_sql, $url_query
  4614. );
  4615. if ($header_shown) {
  4616. $results_operations_html .= '</fieldset><br />';
  4617. }
  4618. return $results_operations_html;
  4619. } // end of the '_getResultsOperations()' function
  4620. /**
  4621. * Verifies what to do with non-printable contents (binary or BLOB)
  4622. * in Browse mode.
  4623. *
  4624. * @param string $category BLOB|BINARY|GEOMETRY
  4625. * @param string $content the binary content
  4626. * @param string $transformation_plugin transformation plugin.
  4627. * Can also be the default function:
  4628. * PMA_mimeDefaultFunction
  4629. * @param array $transform_options transformation parameters
  4630. * @param string $default_function default transformation function
  4631. * @param object $meta the meta-information about the field
  4632. * @param array $url_params parameters that should go to the
  4633. * download link
  4634. *
  4635. * @return mixed string or float
  4636. *
  4637. * @access private
  4638. *
  4639. * @see _getDataCellForBlobColumns(),
  4640. * _getDataCellForGeometryColumns(),
  4641. * _getDataCellForNonNumericAndNonBlobColumns(),
  4642. * _getSortedColumnMessage()
  4643. */
  4644. private function _handleNonPrintableContents(
  4645. $category, $content, $transformation_plugin, $transform_options,
  4646. $default_function, $meta, $url_params = array()
  4647. ) {
  4648. $result = '[' . $category;
  4649. if (isset($content)) {
  4650. $size = strlen($content);
  4651. $display_size = PMA_Util::formatByteDown($size, 3, 1);
  4652. $result .= ' - ' . $display_size[0] . ' ' . $display_size[1];
  4653. } else {
  4654. $result .= ' - NULL';
  4655. $size = 0;
  4656. }
  4657. $result .= ']';
  4658. // if we want to use a text transformation on a BLOB column
  4659. if (gettype($transformation_plugin) == "object"
  4660. && (strpos($transformation_plugin->getMIMESubtype(), 'Octetstream')
  4661. || strpos($transformation_plugin->getMIMEtype(), 'Text') !== false)
  4662. ) {
  4663. $result = $content;
  4664. }
  4665. if ($size > 0) {
  4666. if ($default_function != $transformation_plugin) {
  4667. $result = $transformation_plugin->applyTransformation(
  4668. $result,
  4669. $transform_options,
  4670. $meta
  4671. );
  4672. } else {
  4673. $result = $this->$default_function($result, array(), $meta);
  4674. if (stristr($meta->type, self::BLOB_FIELD)
  4675. && $_SESSION['tmpval']['display_blob']
  4676. ) {
  4677. // in this case, restart from the original $content
  4678. $result = $this->_displayBinaryAsPrintable($content, 'blob');
  4679. }
  4680. /* Create link to download */
  4681. if (count($url_params) > 0) {
  4682. $result = '<a href="tbl_get_field.php'
  4683. . PMA_URL_getCommon($url_params)
  4684. . '" class="disableAjax">'
  4685. . $result . '</a>';
  4686. }
  4687. }
  4688. }
  4689. return($result);
  4690. } // end of the '_handleNonPrintableContents()' function
  4691. /**
  4692. * Prepares the displayable content of a data cell in Browse mode,
  4693. * taking into account foreign key description field and transformations
  4694. *
  4695. * @param string $class css classes for the td element
  4696. * @param bool $condition_field whether the column is a part of the
  4697. * where clause
  4698. * @param array $analyzed_sql the analyzed query
  4699. * @param object $meta the meta-information about the field
  4700. * @param array $map the list of relations
  4701. * @param string $data data
  4702. * @param string $transformation_plugin transformation plugin.
  4703. * Can also be the default function:
  4704. * PMA_mimeDefaultFunction
  4705. * @param string $default_function default function
  4706. * @param string $nowrap 'nowrap' if the content should not
  4707. * be wrapped
  4708. * @param string $where_comparison data for the where clause
  4709. * @param array $transform_options array of options for transformation
  4710. * @param bool $is_field_truncated whether the field is truncated
  4711. *
  4712. * @return string formatted data
  4713. *
  4714. * @access private
  4715. *
  4716. * @see _getDataCellForNumericColumns(), _getDataCellForGeometryColumns(),
  4717. * _getDataCellForNonNumericAndNonBlobColumns(),
  4718. *
  4719. */
  4720. private function _getRowData(
  4721. $class, $condition_field, $analyzed_sql, $meta, $map, $data,
  4722. $transformation_plugin, $default_function, $nowrap, $where_comparison,
  4723. $transform_options, $is_field_truncated
  4724. ) {
  4725. $relational_display = $_SESSION['tmpval']['relational_display'];
  4726. $printview = $this->__get('printview');
  4727. $result = '<td data-decimals="' . $meta->decimals . '" data-type="'
  4728. . $meta->type . '" class="'
  4729. . $this->_addClass(
  4730. $class, $condition_field, $meta, $nowrap,
  4731. $is_field_truncated, $transformation_plugin, $default_function
  4732. )
  4733. . '">';
  4734. if (isset($analyzed_sql[0]['select_expr'])
  4735. && is_array($analyzed_sql[0]['select_expr'])
  4736. ) {
  4737. foreach ($analyzed_sql[0]['select_expr']
  4738. as $select_expr_position => $select_expr
  4739. ) {
  4740. $alias = $analyzed_sql[0]['select_expr']
  4741. [$select_expr_position]['alias'];
  4742. if (!isset($alias) || !strlen($alias)) {
  4743. continue;
  4744. } // end if
  4745. $true_column = $analyzed_sql[0]['select_expr']
  4746. [$select_expr_position]['column'];
  4747. if ($alias == $meta->name) {
  4748. // this change in the parameter does not matter
  4749. // outside of the function
  4750. $meta->name = $true_column;
  4751. } // end if
  4752. } // end foreach
  4753. } // end if
  4754. if (isset($map[$meta->name])) {
  4755. // Field to display from the foreign table?
  4756. if (isset($map[$meta->name][2]) && strlen($map[$meta->name][2])) {
  4757. $dispsql = 'SELECT '
  4758. . PMA_Util::backquote($map[$meta->name][2])
  4759. . ' FROM '
  4760. . PMA_Util::backquote($map[$meta->name][3])
  4761. . '.'
  4762. . PMA_Util::backquote($map[$meta->name][0])
  4763. . ' WHERE '
  4764. . PMA_Util::backquote($map[$meta->name][1])
  4765. . $where_comparison;
  4766. $dispresult = $GLOBALS['dbi']->tryQuery(
  4767. $dispsql,
  4768. null,
  4769. PMA_DatabaseInterface::QUERY_STORE
  4770. );
  4771. if ($dispresult && $GLOBALS['dbi']->numRows($dispresult) > 0) {
  4772. list($dispval) = $GLOBALS['dbi']->fetchRow($dispresult, 0);
  4773. } else {
  4774. $dispval = __('Link not found!');
  4775. }
  4776. @$GLOBALS['dbi']->freeResult($dispresult);
  4777. } else {
  4778. $dispval = '';
  4779. } // end if... else...
  4780. if (isset($printview) && ($printview == '1')) {
  4781. $result .= ($transformation_plugin != $default_function
  4782. ? $transformation_plugin->applyTransformation(
  4783. $data,
  4784. $transform_options,
  4785. $meta
  4786. )
  4787. : $this->$default_function($data)
  4788. )
  4789. . ' <code>[-&gt;' . $dispval . ']</code>';
  4790. } else {
  4791. if ($relational_display == self::RELATIONAL_KEY) {
  4792. // user chose "relational key" in the display options, so
  4793. // the title contains the display field
  4794. $title = (! empty($dispval))
  4795. ? ' title="' . htmlspecialchars($dispval) . '"'
  4796. : '';
  4797. } else {
  4798. $title = ' title="' . htmlspecialchars($data) . '"';
  4799. }
  4800. $_url_params = array(
  4801. 'db' => $map[$meta->name][3],
  4802. 'table' => $map[$meta->name][0],
  4803. 'pos' => '0',
  4804. 'sql_query' => 'SELECT * FROM '
  4805. . PMA_Util::backquote(
  4806. $map[$meta->name][3]
  4807. ) . '.'
  4808. . PMA_Util::backquote(
  4809. $map[$meta->name][0]
  4810. )
  4811. . ' WHERE '
  4812. . PMA_Util::backquote(
  4813. $map[$meta->name][1]
  4814. )
  4815. . $where_comparison,
  4816. );
  4817. $result .= '<a class="ajax" href="sql.php'
  4818. . PMA_URL_getCommon($_url_params)
  4819. . '"' . $title . '>';
  4820. if ($transformation_plugin != $default_function) {
  4821. // always apply a transformation on the real data,
  4822. // not on the display field
  4823. $result .= $transformation_plugin->applyTransformation(
  4824. $data,
  4825. $transform_options,
  4826. $meta
  4827. );
  4828. } else {
  4829. if ($relational_display == self::RELATIONAL_DISPLAY_COLUMN) {
  4830. // user chose "relational display field" in the
  4831. // display options, so show display field in the cell
  4832. $result .= $this->$default_function($dispval);
  4833. } else {
  4834. // otherwise display data in the cell
  4835. $result .= $this->$default_function($data);
  4836. }
  4837. }
  4838. $result .= '</a>';
  4839. }
  4840. } else {
  4841. $result .= ($transformation_plugin != $default_function
  4842. ? $transformation_plugin->applyTransformation(
  4843. $data,
  4844. $transform_options,
  4845. $meta
  4846. )
  4847. : $this->$default_function($data)
  4848. );
  4849. }
  4850. // create hidden field if results from structure table
  4851. if (isset($_GET['browse_distinct']) && ($_GET['browse_distinct'] == 1)) {
  4852. $where_comparison = " = '" . $data . "'";
  4853. $_url_params_for_show_data_row = array(
  4854. 'db' => $this->__get('db'),
  4855. 'table' => $meta->orgtable,
  4856. 'pos' => '0',
  4857. 'sql_query' => 'SELECT * FROM '
  4858. . PMA_Util::backquote($this->__get('db'))
  4859. . '.' . PMA_Util::backquote($meta->orgtable)
  4860. . ' WHERE '
  4861. . PMA_Util::backquote($meta->orgname)
  4862. . $where_comparison,
  4863. );
  4864. $result .= '<input type="hidden" class="data_browse_link" value="'
  4865. . PMA_URL_getCommon($_url_params_for_show_data_row) . '" />';
  4866. }
  4867. $result .= '</td>' . "\n";
  4868. return $result;
  4869. } // end of the '_getRowData()' function
  4870. /**
  4871. * Prepares a checkbox for multi-row submits
  4872. *
  4873. * @param string $del_url delete url
  4874. * @param array $is_display array with explicit indexes for all
  4875. * the display elements
  4876. * @param string $row_no the row number
  4877. * @param string $where_clause_html url encoded where clause
  4878. * @param array $condition_array array of conditions in the where clause
  4879. * @param string $del_query delete query
  4880. * @param string $id_suffix suffix for the id
  4881. * @param string $class css classes for the td element
  4882. *
  4883. * @return string the generated HTML
  4884. *
  4885. * @access private
  4886. *
  4887. * @see _getTableBody(), _getCheckboxAndLinks()
  4888. */
  4889. private function _getCheckboxForMultiRowSubmissions(
  4890. $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
  4891. $del_query, $id_suffix, $class
  4892. ) {
  4893. $ret = '';
  4894. if (! empty($del_url) && $is_display['del_lnk'] != self::KILL_PROCESS) {
  4895. $ret .= '<td ';
  4896. if (! empty($class)) {
  4897. $ret .= 'class="' . $class . '"';
  4898. }
  4899. $ret .= ' class="center">'
  4900. . '<input type="checkbox" id="id_rows_to_delete'
  4901. . $row_no . $id_suffix
  4902. . '" name="rows_to_delete[' . $row_no . ']"'
  4903. . ' class="multi_checkbox checkall"'
  4904. . ' value="' . $where_clause_html . '" '
  4905. . ' />'
  4906. . '<input type="hidden" class="condition_array" value="'
  4907. . htmlspecialchars(json_encode($condition_array)) . '" />'
  4908. . ' </td>';
  4909. }
  4910. return $ret;
  4911. } // end of the '_getCheckboxForMultiRowSubmissions()' function
  4912. /**
  4913. * Prepares an Edit link
  4914. *
  4915. * @param string $edit_url edit url
  4916. * @param string $class css classes for td element
  4917. * @param string $edit_str text for the edit link
  4918. * @param string $where_clause where clause
  4919. * @param string $where_clause_html url encoded where clause
  4920. *
  4921. * @return string the generated HTML
  4922. *
  4923. * @access private
  4924. *
  4925. * @see _getTableBody(), _getCheckboxAndLinks()
  4926. */
  4927. private function _getEditLink(
  4928. $edit_url, $class, $edit_str, $where_clause, $where_clause_html
  4929. ) {
  4930. $ret = '';
  4931. if (! empty($edit_url)) {
  4932. $ret .= '<td class="' . $class . ' center" ' . ' ><span class="nowrap">'
  4933. . PMA_Util::linkOrButton(
  4934. $edit_url, $edit_str, array(), false
  4935. );
  4936. /*
  4937. * Where clause for selecting this row uniquely is provided as
  4938. * a hidden input. Used by jQuery scripts for handling grid editing
  4939. */
  4940. if (! empty($where_clause)) {
  4941. $ret .= '<input type="hidden" class="where_clause" value ="'
  4942. . $where_clause_html . '" />';
  4943. }
  4944. $ret .= '</span></td>';
  4945. }
  4946. return $ret;
  4947. } // end of the '_getEditLink()' function
  4948. /**
  4949. * Prepares an Copy link
  4950. *
  4951. * @param string $copy_url copy url
  4952. * @param string $copy_str text for the copy link
  4953. * @param string $where_clause where clause
  4954. * @param string $where_clause_html url encoded where clause
  4955. * @param string $class css classes for the td element
  4956. *
  4957. * @return string the generated HTML
  4958. *
  4959. * @access private
  4960. *
  4961. * @see _getTableBody(), _getCheckboxAndLinks()
  4962. */
  4963. private function _getCopyLink(
  4964. $copy_url, $copy_str, $where_clause, $where_clause_html, $class
  4965. ) {
  4966. $ret = '';
  4967. if (! empty($copy_url)) {
  4968. $ret .= '<td class="';
  4969. if (! empty($class)) {
  4970. $ret .= $class . ' ';
  4971. }
  4972. $ret .= 'center" ' . ' ><span class="nowrap">'
  4973. . PMA_Util::linkOrButton(
  4974. $copy_url, $copy_str, array(), false
  4975. );
  4976. /*
  4977. * Where clause for selecting this row uniquely is provided as
  4978. * a hidden input. Used by jQuery scripts for handling grid editing
  4979. */
  4980. if (! empty($where_clause)) {
  4981. $ret .= '<input type="hidden" class="where_clause" value="'
  4982. . $where_clause_html . '" />';
  4983. }
  4984. $ret .= '</span></td>';
  4985. }
  4986. return $ret;
  4987. } // end of the '_getCopyLink()' function
  4988. /**
  4989. * Prepares a Delete link
  4990. *
  4991. * @param string $del_url delete url
  4992. * @param string $del_str text for the delete link
  4993. * @param string $js_conf text for the JS confirmation
  4994. * @param string $class css classes for the td element
  4995. *
  4996. * @return string the generated HTML
  4997. *
  4998. * @access private
  4999. *
  5000. * @see _getTableBody(), _getCheckboxAndLinks()
  5001. */
  5002. private function _getDeleteLink($del_url, $del_str, $js_conf, $class)
  5003. {
  5004. $ret = '';
  5005. if (! empty($del_url)) {
  5006. $ret .= '<td class="';
  5007. if (! empty($class)) {
  5008. $ret .= $class . ' ';
  5009. }
  5010. $ajax = PMA_Response::getInstance()->isAjax() ? ' ajax' : '';
  5011. $ret .= 'center" ' . ' >'
  5012. . PMA_Util::linkOrButton(
  5013. $del_url, $del_str, array('class' => 'delete_row' . $ajax), false
  5014. )
  5015. . '<div class="hide">' . $js_conf . '</div>'
  5016. . '</td>';
  5017. }
  5018. return $ret;
  5019. } // end of the '_getDeleteLink()' function
  5020. /**
  5021. * Prepare checkbox and links at some position (left or right)
  5022. * (only called for horizontal mode)
  5023. *
  5024. * @param string $position the position of the checkbox and links
  5025. * @param string $del_url delete url
  5026. * @param array $is_display array with explicit indexes for all the
  5027. * display elements
  5028. * @param string $row_no row number
  5029. * @param string $where_clause where clause
  5030. * @param string $where_clause_html url encoded where clause
  5031. * @param array $condition_array array of conditions in the where clause
  5032. * @param string $del_query delete query
  5033. * @param string $id_suffix suffix for the id
  5034. * @param string $edit_url edit url
  5035. * @param string $copy_url copy url
  5036. * @param string $class css classes for the td elements
  5037. * @param string $edit_str text for the edit link
  5038. * @param string $copy_str text for the copy link
  5039. * @param string $del_str text for the delete link
  5040. * @param string $js_conf text for the JS confirmation
  5041. *
  5042. * @return string the generated HTML
  5043. *
  5044. * @access private
  5045. *
  5046. * @see _getPlacedLinks()
  5047. */
  5048. private function _getCheckboxAndLinks(
  5049. $position, $del_url, $is_display, $row_no, $where_clause,
  5050. $where_clause_html, $condition_array, $del_query, $id_suffix,
  5051. $edit_url, $copy_url, $class, $edit_str, $copy_str, $del_str, $js_conf
  5052. ) {
  5053. $ret = '';
  5054. if ($position == self::POSITION_LEFT) {
  5055. $ret .= $this->_getCheckboxForMultiRowSubmissions(
  5056. $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
  5057. $del_query, $id_suffix = '_left', ''
  5058. );
  5059. $ret .= $this->_getEditLink(
  5060. $edit_url, $class, $edit_str, $where_clause, $where_clause_html
  5061. );
  5062. $ret .= $this->_getCopyLink(
  5063. $copy_url, $copy_str, $where_clause, $where_clause_html, ''
  5064. );
  5065. $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
  5066. } elseif ($position == self::POSITION_RIGHT) {
  5067. $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
  5068. $ret .= $this->_getCopyLink(
  5069. $copy_url, $copy_str, $where_clause, $where_clause_html, ''
  5070. );
  5071. $ret .= $this->_getEditLink(
  5072. $edit_url, $class, $edit_str, $where_clause, $where_clause_html
  5073. );
  5074. $ret .= $this->_getCheckboxForMultiRowSubmissions(
  5075. $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
  5076. $del_query, $id_suffix = '_right', ''
  5077. );
  5078. } else { // $position == self::POSITION_NONE
  5079. $ret .= $this->_getCheckboxForMultiRowSubmissions(
  5080. $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
  5081. $del_query, $id_suffix = '_left', ''
  5082. );
  5083. }
  5084. return $ret;
  5085. } // end of the '_getCheckboxAndLinks()' function
  5086. /**
  5087. * Replace some html-unfriendly stuff
  5088. *
  5089. * @param string $buffer String to process
  5090. *
  5091. * @return String Escaped and cleaned up text suitable for html.
  5092. *
  5093. * @access private
  5094. *
  5095. * @see _getDataCellForBlobField(), _getRowData(),
  5096. * _handleNonPrintableContents()
  5097. */
  5098. private function _mimeDefaultFunction($buffer)
  5099. {
  5100. $buffer = htmlspecialchars($buffer);
  5101. $buffer = str_replace(
  5102. "\011",
  5103. ' &nbsp;&nbsp;&nbsp;',
  5104. str_replace(' ', ' &nbsp;', $buffer)
  5105. );
  5106. $buffer = preg_replace("@((\015\012)|(\015)|(\012))@", '<br />', $buffer);
  5107. return $buffer;
  5108. }
  5109. /**
  5110. * Display binary columns as hex string if requested
  5111. * otherwise escape the contents using the best possible way
  5112. *
  5113. * @param string $content String to parse
  5114. * @param string $binary_or_blob binary' or 'blob'
  5115. * @param int $hexlength optional, get substring
  5116. *
  5117. * @return String Displayable version of the binary string
  5118. *
  5119. * @access private
  5120. *
  5121. * @see _getDataCellForGeometryColumns
  5122. * _getDataCellForNonNumericAndNonBlobColumns
  5123. * _handleNonPrintableContents
  5124. */
  5125. private function _displayBinaryAsPrintable(
  5126. $content, $binary_or_blob, $hexlength = null
  5127. ) {
  5128. if ($binary_or_blob === 'binary'
  5129. && $_SESSION['tmpval']['display_binary_as_hex']
  5130. ) {
  5131. $content = bin2hex($content);
  5132. if ($hexlength !== null) {
  5133. $content = $GLOBALS['PMA_String']->substr($content, $hexlength);
  5134. }
  5135. } elseif (PMA_Util::containsNonPrintableAscii($content)) {
  5136. if (PMA_PHP_INT_VERSION < 50400) {
  5137. $content = htmlspecialchars(
  5138. PMA_Util::replaceBinaryContents(
  5139. $content
  5140. )
  5141. );
  5142. } else {
  5143. // The ENT_SUBSTITUTE option is available for PHP >= 5.4.0
  5144. $content = htmlspecialchars(
  5145. PMA_Util::replaceBinaryContents(
  5146. $content
  5147. ),
  5148. ENT_SUBSTITUTE
  5149. );
  5150. }
  5151. }
  5152. return $content;
  5153. }
  5154. }
  5155. ?>